Advertisement
LDDestroier

Workspace (Pastebin)

Jun 20th, 2019
483
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 38.13 KB | None | 0 0
  1. -- Workspaces for ComputerCraft
  2. -- by LDDestroier
  3.  
  4. local tArg = {...}
  5.  
  6. local instances = {}
  7. local configPath = ".workspace_config"
  8.  
  9. local config = {
  10.     workspaceMoveSpeed = 0.15,
  11.     defaultProgram = "rom/programs/shell.lua",
  12.     timesRan = 0,
  13.     useDefaultProgramWhenStarting = true,
  14.     doPauseClockAndTime = true,
  15.     skipAcrossEmptyWorkspaces = true,
  16.     showInactiveFrame = true,
  17.     doTrippyVoid = false,
  18.     flipTheFuckOut = false,
  19.     WSmap = {
  20.         {true,true,true},
  21.         {true,true,true},
  22.         {true,true,true},
  23.     }
  24. }
  25.  
  26. -- values determined after every new/removed workspace
  27. local gridWidth, gridHeight, gridMinX, gridMinY
  28.  
  29. -- used by argument parser
  30. local argList, argErrors
  31.  
  32. local getMapSize = function()
  33.     local xmax, xmin, ymax, ymin = -math.huge, math.huge, -math.huge, math.huge
  34.     local isRowEmpty
  35.     for y, v in pairs(config.WSmap) do
  36.         isRowEmpty = true
  37.         for x, vv in pairs(v) do
  38.             if vv then
  39.                 xmin = math.min(xmin, x)
  40.                 xmax = math.max(xmax, x)
  41.                 isRowEmpty = false
  42.             end
  43.         end
  44.         if not isRowEmpty then
  45.             ymin = math.min(ymin, y)
  46.             ymax = math.max(ymax, y)
  47.         end
  48.     end
  49.     return xmax, ymax, xmin, ymin
  50. end
  51.  
  52. local readFile = function(path)
  53.     local file = fs.open(path, "r")
  54.     local contents = file.readAll()
  55.     file.close()
  56.     return contents
  57. end
  58.  
  59. local saveConfig = function()
  60.     local file = fs.open(configPath, "w")
  61.     file.write( textutils.serialize(config) )
  62.     file.close()
  63. end
  64.  
  65. local loadConfig = function()
  66.     if fs.exists(configPath) then
  67.         local contents = readFile(configPath)
  68.         local newConfig = textutils.unserialize(contents)
  69.         for k,v in pairs(newConfig) do
  70.             config[k] = v
  71.         end
  72.     end
  73. end
  74.  
  75. loadConfig()
  76. saveConfig()
  77.  
  78. -- lists all keys currently pressed
  79. local keysDown = {}
  80.  
  81. -- amount of time (seconds) until workspace indicator disappears
  82. local workspaceIndicatorDuration = 0.6
  83.  
  84. -- if held down while moving workspace, will swap positions
  85. local swapKey = keys.tab
  86.  
  87. local scr_x, scr_y = term.getSize()
  88. local windowWidth = scr_x
  89. local windowHeight = scr_y
  90. local doDrawWorkspaceIndicator = false
  91.  
  92. local scroll = {0,0}        -- change this value when scrolling
  93. local realScroll = {0,0}    -- this value changes depending on scroll for smoothness purposes
  94. local focus = {}            -- currently focused instance, declared when loading from config
  95.  
  96. local isRunning = true
  97.  
  98. local cwrite = function(text, y, terminal)
  99.     terminal = terminal or term.current()
  100.     local cx, cy = terminal.getCursorPos()
  101.     local sx, sy = terminal.getSize()
  102.     terminal.setCursorPos(sx / 2 - #text / 2, y or (sy / 2))
  103.     terminal.write(text)
  104. end
  105.  
  106. -- start up lddterm (I'm starting to think I should've used window API)
  107. local lddterm = {}
  108. lddterm.alwaysRender = false        -- renders after any and all screen-changing functions.
  109. lddterm.useColors = true            -- normal computers do not allow color, but this variable doesn't do anything yet
  110. lddterm.baseTerm = term.current()   -- will draw to this terminal
  111. lddterm.transformation = nil        -- will modify the current buffer as an NFT image before rendering
  112. lddterm.cursorTransformation = nil  -- will modify the cursor position
  113. lddterm.drawFunction = nil          -- will draw using this function instead of basic NFT drawing
  114. lddterm.adjustX = 0                 -- moves entire screen X
  115. lddterm.adjustY = 0                 -- moves entire screen Y
  116. lddterm.selectedWindow = 1          -- determines which window controls the cursor
  117. lddterm.windows = {}                -- internal list of all lddterm windows
  118. -- backdropColors used for the void outside of windows, if using rainbow void
  119. local backdropColors = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"}
  120.  
  121. -- draws one of three things:
  122. --  1. workspace grid indicator
  123. --  2. "PAUSED" screen
  124. --  3. "UNPAUSED" screen
  125. local drawWorkspaceIndicator = function(terminal, wType)
  126.     gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  127.     terminal = terminal or term.current()
  128.     if wType == 1 then
  129.         for y = gridMinY - 1, gridHeight + 1 do
  130.             for x = gridMinX - 1, gridWidth + 1 do
  131.                 terminal.setCursorPos((x - gridMinX) + scr_x / 2 - (gridWidth - gridMinX) / 2, (y - gridMinY) + math.ceil(scr_y / 2) - (gridHeight - gridMinY) / 2)
  132.                 if instances[y] then
  133.                     if instances[y][x] then
  134.                         if focus[1] == x and focus[2] == y then
  135.                             terminal.blit(" ", "8", "8")
  136.                         elseif instances[y][x].active then
  137.                             terminal.blit(" ", "7", "7")
  138.                         else
  139.                             terminal.blit(" ", "0", "f")
  140.                         end
  141.                     else
  142.                         terminal.blit(" ", "0", "0")
  143.                     end
  144.                 else
  145.                     terminal.blit(" ", "0", "0")
  146.                 end
  147.             end
  148.         end
  149.     elseif wType == 2 then
  150.         local msg = "PAUSED"
  151.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2 - 1)
  152.         terminal.blit((" "):rep(#msg + 2), ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  153.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2)
  154.         terminal.blit(" " .. msg .. " ", ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  155.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2 + 1)
  156.         terminal.blit((" "):rep(#msg + 2), ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  157.     elseif wType == 3 then
  158.         local msg = "UNPAUSED"
  159.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2 - 1)
  160.         terminal.blit((" "):rep(#msg + 2), ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  161.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2)
  162.         terminal.blit(" " .. msg .. " ", ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  163.         terminal.setCursorPos(scr_x / 2 - #msg / 2 - 2, scr_y / 2 + 1)
  164.         terminal.blit((" "):rep(#msg + 2), ("f"):rep(#msg + 2), ("0"):rep(#msg + 2))
  165.     end
  166. end
  167.  
  168. -- converts blit colors to colors api, and back
  169. local to_colors, to_blit = {
  170.     [' '] = 0,
  171.     ['0'] = 1,
  172.     ['1'] = 2,
  173.     ['2'] = 4,
  174.     ['3'] = 8,
  175.     ['4'] = 16,
  176.     ['5'] = 32,
  177.     ['6'] = 64,
  178.     ['7'] = 128,
  179.     ['8'] = 256,
  180.     ['9'] = 512,
  181.     ['a'] = 1024,
  182.     ['b'] = 2048,
  183.     ['c'] = 4096,
  184.     ['d'] = 8192,
  185.     ['e'] = 16384,
  186.     ['f'] = 32768,
  187. }, {}
  188. for k,v in pairs(to_colors) do
  189.     to_blit[v] = k
  190. end
  191.  
  192. -- separates string into table based on divider
  193. local explode = function(div, str, replstr, includeDiv)
  194.     if (div == '') then
  195.         return false
  196.     end
  197.     local pos, arr = 0, {}
  198.     for st, sp in function() return string.find(str, div, pos, false) end do
  199.         table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
  200.         pos = sp + 1
  201.     end
  202.     table.insert(arr, string.sub(replstr or str, pos))
  203.     return arr
  204. end
  205.  
  206. -- determines the size of the terminal before rendering always
  207. local determineScreenSize = function()
  208.     scr_x, scr_y = lddterm.baseTerm.getSize()
  209.     lddterm.screenWidth = scr_x
  210.     lddterm.screenHeight = scr_y
  211. end
  212.  
  213. determineScreenSize()
  214.  
  215. -- takes two or more windows and checks if the first of them overlap the other(s)
  216. lddterm.checkWindowOverlap = function(window, ...)
  217.     if #lddterm.windows < 2 then
  218.         return false
  219.     end
  220.     local list, win = {...}
  221.     for i = 1, #list do
  222.         win = list[i]
  223.         if win ~= window then
  224.  
  225.             if (
  226.                 window.x < win.x + win.width and
  227.                 win.x < window.x + window.width and
  228.                 window.y < win.y + win.height and
  229.                 win.y < window.y + window.height
  230.             ) then
  231.                 return true
  232.             end
  233.  
  234.         end
  235.     end
  236.     return false
  237. end
  238.  
  239. local fixCursorPos = function()
  240.     local cx, cy
  241.     if lddterm.windows[lddterm.selectedWindow] then
  242.         if lddterm.cursorTransformation then
  243.             cx, cy = lddterm.cursorTransformation(
  244.                 lddterm.windows[lddterm.selectedWindow].cursor[1],
  245.                 lddterm.windows[lddterm.selectedWindow].cursor[2]
  246.             )
  247.             lddterm.baseTerm.setCursorPos(
  248.                 cx + lddterm.windows[lddterm.selectedWindow].x - 1,
  249.                 cy + lddterm.windows[lddterm.selectedWindow].y - 1
  250.             )
  251.         else
  252.             lddterm.baseTerm.setCursorPos(
  253.                 -1 + lddterm.windows[lddterm.selectedWindow].cursor[1] + lddterm.windows[lddterm.selectedWindow].x,
  254.                 lddterm.windows[lddterm.selectedWindow].cursor[2] + lddterm.windows[lddterm.selectedWindow].y - 1
  255.             )
  256.         end
  257.         lddterm.baseTerm.setCursorBlink(lddterm.windows[lddterm.selectedWindow].blink)
  258.     end
  259. end
  260.  
  261. -- renders the screen with optional transformation function
  262. lddterm.render = function(transformation, drawFunction)
  263.     -- determine new screen size and change lddterm screen to fit
  264.     old_scr_x, old_scr_y = scr_x, scr_y
  265.     determineScreenSize()
  266.     if old_scr_x ~= scr_x or old_scr_y ~= scr_y then
  267.         lddterm.baseTerm.clear()
  268.     end
  269.     local image = lddterm.screenshot()
  270.     if type(transformation) == "function" then
  271.         image = transformation(image)
  272.     end
  273.     if drawFunction then
  274.         drawFunction(image, lddterm.baseTerm)
  275.     else
  276.         for y = 1, #image[1] do
  277.             lddterm.baseTerm.setCursorPos(1 + lddterm.adjustX, y + lddterm.adjustY)
  278.             lddterm.baseTerm.blit(image[1][y], image[2][y], image[3][y])
  279.         end
  280.     end
  281.     if doDrawWorkspaceIndicator then
  282.         drawWorkspaceIndicator(nil, doDrawWorkspaceIndicator)
  283.     end
  284.     fixCursorPos()
  285. end
  286.  
  287. lddterm.newWindow = function(width, height, x, y, meta)
  288.     meta = meta or {}
  289.     local window = {
  290.         width = math.floor(width),
  291.         height = math.floor(height),
  292.         blink = true,
  293.         cursor = meta.cursor or {1, 1},
  294.         colors = meta.colors or {"0", "f"},
  295.         clearChar = meta.clearChar or " ",
  296.         visible = meta.visible or true,
  297.         x = math.floor(x) or 1,
  298.         y = math.floor(y) or 1,
  299.         buffer = {{},{},{}},
  300.     }
  301.     for y = 1, height do
  302.         window.buffer[1][y] = {}
  303.         window.buffer[2][y] = {}
  304.         window.buffer[3][y] = {}
  305.         for x = 1, width do
  306.             window.buffer[1][y][x] = window.clearChar
  307.             window.buffer[2][y][x] = window.colors[1]
  308.             window.buffer[3][y][x] = window.colors[2]
  309.         end
  310.     end
  311.  
  312.     window.handle = {}
  313.     window.handle.setCursorPos = function(x, y)
  314.         window.cursor = {x, y}
  315.         fixCursorPos()
  316.     end
  317.     window.handle.getCursorPos = function()
  318.         return window.cursor[1], window.cursor[2]
  319.     end
  320.     window.handle.setCursorBlink = function(blink)
  321.         window.blink = blink or false
  322.     end
  323.     window.handle.getCursorBlink = function()
  324.         return window.blink
  325.     end
  326.     window.handle.scroll = function(amount)
  327.         if amount > 0 then
  328.             for i = 1, amount do
  329.                 for c = 1, 3 do
  330.                     table.remove(window.buffer[c], 1)
  331.                     window.buffer[c][window.height] = {}
  332.                     for xx = 1, width do
  333.                         window.buffer[c][window.height][xx] = (
  334.                             c == 1 and window.clearChar or
  335.                             c == 2 and window.colors[1] or
  336.                             c == 3 and window.colors[2]
  337.                         )
  338.                     end
  339.                 end
  340.             end
  341.         elseif amount < 0 then
  342.             for i = 1, -amount do
  343.                 for c = 1, 3 do
  344.                     window.buffer[c][window.height] = nil
  345.                     table.insert(window.buffer[c], 1, {})
  346.                     for xx = 1, width do
  347.                         window.buffer[c][1][xx] = (
  348.                             c == 1 and window.clearChar or
  349.                             c == 2 and window.colors[1] or
  350.                             c == 3 and window.colors[2]
  351.                         )
  352.                     end
  353.                 end
  354.             end
  355.         end
  356.         if lddterm.alwaysRender then
  357.             lddterm.render(lddterm.transformation, lddterm.drawFunction)
  358.         end
  359.     end
  360.     window.handle.write = function(text)
  361.         assert(text ~= nil, "expected string 'text'")
  362.         text = tostring(text)
  363.         local cx = math.floor(window.cursor[1])
  364.         local cy = math.floor(window.cursor[2])
  365.         for i = 1, #text do
  366.             if cx >= 1 and cx <= window.width and cy >= 1 and cy <= window.height then
  367.                 window.buffer[1][cy][cx] = text:sub(i,i)
  368.                 window.buffer[2][cy][cx] = window.colors[1]
  369.                 window.buffer[3][cy][cx] = window.colors[2]
  370.             end
  371.             cx = math.min(cx + 1, window.width + 1)
  372.         end
  373.         window.cursor = {cx, cy}
  374.         if lddterm.alwaysRender then
  375.             lddterm.render(lddterm.transformation, lddterm.drawFunction)
  376.         end
  377.     end
  378.     window.handle.blit = function(char, textCol, backCol)
  379.         if type(char) == "number" then
  380.             char = tostring(char)
  381.         end
  382.         if type(textCol) == "number" then
  383.             textCol = tostring(textCol)
  384.         end
  385.         if type(backCol) == "number" then
  386.             backCol = tostring(backCol)
  387.         end
  388.         assert(char ~= nil, "expected string 'char'")
  389.         local cx = math.floor(window.cursor[1])
  390.         local cy = math.floor(window.cursor[2])
  391.         for i = 1, #char do
  392.             if cx >= 1 and cx <= window.width and cy >= 1 and cy <= window.height then
  393.                 window.buffer[1][cy][cx] = char:sub(i,i)
  394.                 window.buffer[2][cy][cx] = textCol:sub(i,i)
  395.                 window.buffer[3][cy][cx] = backCol:sub(i,i)
  396.             end
  397.             cx = cx + 1
  398.         end
  399.         window.cursor = {cx, cy}
  400.         if lddterm.alwaysRender then
  401.             lddterm.render(lddterm.transformation, lddterm.drawFunction)
  402.         end
  403.     end
  404.     window.handle.clear = function(char)
  405.         local cx = 1
  406.         char = type(char) == "string" and char or " "
  407.         for y = 1, window.height do
  408.             for x = 1, window.width do
  409.                 if char then
  410.                     cx = (x % #char) + 1
  411.                 end
  412.                 window.buffer[1][y][x] = char and char:sub(cx, cx) or window.clearChar
  413.                 window.buffer[2][y][x] = window.colors[1]
  414.                 window.buffer[3][y][x] = window.colors[2]
  415.             end
  416.         end
  417.         if lddterm.alwaysRender then
  418.             lddterm.render(lddterm.transformation, lddterm.drawFunction)
  419.         end
  420.     end
  421.     window.handle.clearLine = function(cy, char)
  422.         cy = math.floor(cy or window.cursor[2])
  423.         char = type(char) == "string" and char or " "
  424.         local cx = 1
  425.         if window.buffer[1][cy or window.cursor[2]] then
  426.             for x = 1, window.width do
  427.                 if char then
  428.                     cx = (x % #char) + 1
  429.                 end
  430.                 window.buffer[1][cy or window.cursor[2]][x] = char and char:sub(cx, cx) or window.clearChar
  431.                 window.buffer[2][cy or window.cursor[2]][x] = window.colors[1]
  432.                 window.buffer[3][cy or window.cursor[2]][x] = window.colors[2]
  433.             end
  434.             if lddterm.alwaysRender then
  435.                 lddterm.render(lddterm.transformation, lddterm.drawFunction)
  436.             end
  437.         end
  438.     end
  439.     window.handle.getSize = function()
  440.         return window.width, window.height
  441.     end
  442.     window.handle.isColor = function()
  443.         return lddterm.useColors
  444.     end
  445.     window.handle.isColour = window.handle.isColor
  446.     window.handle.setTextColor = function(color)
  447.         if to_blit[color] then
  448.             window.colors[1] = to_blit[color]
  449.         end
  450.     end
  451.     window.handle.setTextColour = window.handle.setTextColor
  452.     window.handle.setBackgroundColor = function(color)
  453.         if to_blit[color] then
  454.             window.colors[2] = to_blit[color]
  455.         end
  456.     end
  457.     window.handle.setBackgroundColour = window.handle.setBackgroundColor
  458.     window.handle.getTextColor = function()
  459.         return to_colors[window.colors[1]] or colors.white
  460.     end
  461.     window.handle.getTextColour = window.handle.getTextColor
  462.     window.handle.getBackgroundColor = function()
  463.         return to_colors[window.colors[2]] or colors.black
  464.     end
  465.     window.handle.getBackgroundColour = window.handle.getBackgroundColor
  466.     window.handle.reposition = function(x, y)
  467.         window.x = math.floor(x or window.x)
  468.         window.y = math.floor(y or window.y)
  469.         if lddterm.alwaysRender then
  470.             lddterm.render(lddterm.transformation, lddterm.drawFunction)
  471.         end
  472.     end
  473.     window.handle.setPaletteColor = function(...)
  474.         return lddterm.baseTerm.setPaletteColor(...)
  475.     end
  476.     window.handle.setPaletteColour = window.handle.setPaletteColor
  477.     window.handle.getPaletteColor = function(...)
  478.         return lddterm.baseTerm.getPaletteColor(...)
  479.     end
  480.     window.handle.getPaletteColour = window.handle.getPaletteColor
  481.     window.handle.getPosition = function()
  482.         return window.x, window.y
  483.     end
  484.     window.handle.restoreCursor = function()
  485.         lddterm.baseTerm.setCursorPos(
  486.             -1 + window.cursor[1] + window.x,
  487.             window.cursor[2] + window.y - 1
  488.         )
  489.     end
  490.     window.handle.setVisible = function(visible)
  491.         window.visible = visible or false
  492.     end
  493.  
  494.     window.handle.redraw = lddterm.render
  495.     window.handle.current = window.handle
  496.  
  497.     window.layer = #lddterm.windows + 1
  498.     lddterm.windows[window.layer] = window
  499.  
  500.     return window, window.layer
  501. end
  502.  
  503. lddterm.setLayer = function(window, _layer)
  504.     local layer = math.max(1, math.min(#lddterm.windows, _layer))
  505.  
  506.     local win = window
  507.     table.remove(lddterm.windows, win.layer)
  508.     table.insert(lddterm.windows, layer, win)
  509.  
  510.     if lddterm.alwaysRender then
  511.         lddterm.render(lddterm.transformation, lddterm.drawFunction)
  512.     end
  513.     return true
  514. end
  515.  
  516. local old_scr_x, old_scr_y
  517.  
  518. -- gets screenshot of whole lddterm desktop, OR a single window
  519. lddterm.screenshot = function(window)
  520.     local output = {{},{},{}}
  521.     local line
  522.     if window then
  523.         for y = 1, #window.buffer do
  524.             line = {"","",""}
  525.             for x = 1, #window.buffer do
  526.                 line = {
  527.                     line[1] .. window.buffer[1][y][x],
  528.                     line[2] .. window.buffer[2][y][x],
  529.                     line[3] .. window.buffer[3][y][x]
  530.                 }
  531.             end
  532.             output[1][y] = line[1]
  533.             output[2][y] = line[2]
  534.             output[3][y] = line[3]
  535.         end
  536.     else
  537.         for y = 1, scr_y do
  538.             line = {"","",""}
  539.             for x = 1, scr_x do
  540.  
  541.                 lt, lb = t, b
  542.                 if config.doTrippyVoid then
  543.                     c = string.char(math.random(128, 159))
  544.                     t = backdropColors[1 + math.floor((y - realScroll[2] * scr_y) % #backdropColors)]
  545.                     b = backdropColors[1 + math.floor((x - realScroll[1] * scr_x) % #backdropColors)]
  546.                 else
  547.                     c = string.char( math.max(128, math.random(-5000, 159)) )
  548.                     t = ({"7", "8"})[math.random(1, 2)]
  549.                     b = "f"
  550.                 end
  551.                 for l, v in pairs(lddterm.windows) do
  552.                     if lddterm.windows[l] then
  553.                         if lddterm.windows[l].visible then
  554.                             sx = 1 + x - lddterm.windows[l].x
  555.                             sy = 1 + y - lddterm.windows[l].y
  556.                             if lddterm.windows[l].buffer[1][sy] then
  557.                                 if lddterm.windows[l].buffer[1][sy][sx] then
  558.                                     c = lddterm.windows[l].buffer[1][sy][sx] or c
  559.                                     t = lddterm.windows[l].buffer[2][sy][sx] or t
  560.                                     b = lddterm.windows[l].buffer[3][sy][sx] or b
  561.                                     break
  562.                                 end
  563.                             end
  564.                         end
  565.                     end
  566.                 end
  567.                 line = {
  568.                     line[1] .. c,
  569.                     line[2] .. t,
  570.                     line[3] .. b
  571.                 }
  572.             end
  573.             output[1][y] = line[1]
  574.             output[2][y] = line[2]
  575.             output[3][y] = line[3]
  576.         end
  577.     end
  578.     return output
  579. end
  580.  
  581. local newInstance = function(x, y, program, initialStart)
  582.     x, y = math.floor(x), math.floor(y)
  583.     if instances[y] then
  584.         if instances[y][x] then
  585.             return
  586.         end
  587.     end
  588.     gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  589.     for yy = gridMinY, y do
  590.         instances[yy] = instances[yy] or {}
  591.     end
  592.     instances[y] = instances[y] or {}
  593.     for xx = gridMinX, x do
  594.         instances[y][xx] = instances[y][xx] or false
  595.     end
  596.     local window = lddterm.newWindow(windowWidth, windowHeight, 1, 1)
  597.  
  598.     local instance = {
  599.         x = x,
  600.         y = y,
  601.         active = initialStart,
  602.         program = program or config.defaultProgram,
  603.         window = window,
  604.         timer = {},
  605.         clockMod = 0,
  606.         lastClock = 0,
  607.         timeMod = 0,
  608.         lastTime = 0,
  609.         extraEvents = {},
  610.         paused = false
  611.     }
  612.  
  613.     local func = function()
  614.         term.redirect(window.handle)
  615.  
  616.         local runProgram = function()
  617.             instance.paused = false
  618.             term.setCursorBlink(false)
  619.             if not instance.program or type(instance.program) == "string" then
  620.                 setfenv(function() pcall(shell.run, instance.program) end, instance.env)()
  621.             elseif type(instance.program) == "function" then
  622.                 pcall(function() load(instance.program, nil, nil, instance.env) end)
  623.             end
  624.             instance.extraEvents = {}
  625.             instance.timer = {}
  626.             instance.clockMod = 0
  627.             instance.lastClock = 0
  628.             instance.timeMod = 0
  629.             instance.lastTime = 0
  630.         end
  631.  
  632.         local drawInactiveScreen = function()
  633.             term.setTextColor(colors.white)
  634.             term.setBackgroundColor(colors.black)
  635.             term.clear()
  636.             term.setCursorBlink(false)
  637.  
  638.             if config.showInactiveFrame then
  639.                 if (instance.y + instance.x) % 2 == 0 then
  640.                     term.setTextColor(colors.lightGray)
  641.                 else
  642.                     term.setTextColor(colors.gray)
  643.                 end
  644.                 for y = 1, scr_y do
  645.                     for x = 1, scr_x do
  646.                         if y == 1 or y == scr_y then
  647.                             if x <= 3 or x > scr_x - 3 then
  648.                                 term.setCursorPos(x, y)
  649.                                 term.write("\127")
  650.                             end
  651.                         elseif y <= 3 or y > scr_y - 3 then
  652.                             if x == 1 or x == scr_x then
  653.                                 term.setCursorPos(x, y)
  654.                                 term.write("\127")
  655.                             end
  656.                         end
  657.                     end
  658.                 end
  659.                 term.setTextColor(colors.white)
  660.             end
  661.  
  662.             cwrite("This workspace is inactive.", 0 + scr_y / 2)
  663.             cwrite("Press SPACE to start the workspace.", 1 + scr_y / 2)
  664.             cwrite("(" .. tostring(instance.x) .. ", " .. tostring(instance.y) .. ")", 3 + scr_y / 2)
  665.         end
  666.  
  667.         local evt
  668.         while true do
  669.  
  670.             if initialStart then
  671.                 runProgram()
  672.             end
  673.  
  674.             instance.active = false
  675.             instance.paused = false
  676.             if config.useDefaultProgramWhenStarting then
  677.                 instance.program = config.defaultProgram
  678.             end
  679.  
  680.             drawInactiveScreen()
  681.  
  682.             --coroutine.yield()
  683.  
  684.             repeat
  685.                 evt = {os.pullEventRaw()}
  686.                 if evt[1] == "workspace_swap" then
  687.                     drawInactiveScreen()
  688.                 end
  689.             until (evt[1] == "key" and evt[2] == keys.space) or evt[1] == "terminate"
  690.             sleep(0)
  691.             if evt[1] == "terminate" then
  692.                 isRunning = false
  693.                 return
  694.             end
  695.  
  696.             term.setCursorPos(1,1)
  697.             term.clear()
  698.             term.setCursorBlink(true)
  699.  
  700.             instance.active = true
  701.  
  702.             if not initialStart then
  703.                 runProgram()
  704.             end
  705.  
  706.         end
  707.     end
  708.  
  709.     instances[y][x] = instance
  710.  
  711.     instances[y][x].env = {}
  712.     setmetatable(instances[y][x].env, {__index = _ENV})
  713.  
  714.     instances[y][x].co = coroutine.create(func)
  715. end
  716.  
  717. -- prevents wiseassed-ness
  718. config.workspaceMoveSpeed = math.min(math.max(config.workspaceMoveSpeed, 0.001), 1)
  719.  
  720. local tickDownInstanceTimers = function(x, y)
  721.     timersToDelete = {}
  722.     for id, duration in pairs(instances[y][x].timer) do
  723.         if duration <= 0.05 then
  724.             instances[y][x].extraEvents[#instances[y][x].extraEvents + 1] = {"timer", id}
  725.             timersToDelete[#timersToDelete + 1] = id
  726.         else
  727.             instances[y][x].timer[id] = duration - 0.05
  728.         end
  729.     end
  730.     for i = 1, #timersToDelete do
  731.         instances[y][x].timer[timersToDelete[i]] = nil
  732.     end
  733. end
  734.  
  735. local scrollWindows = function(doScrollWindows, tickDownTimers)
  736.     local changed = false
  737.     local timersToDelete = {}
  738.     local xrand, yrand = 0, 0
  739.     if config.flipTheFuckOut then
  740.         xrand, yrand = math.random(-5, 5) / 60, math.random(-5, 5) / 60
  741.     end
  742.     if doScrollWindows then
  743.         if realScroll[1] < scroll[1] + xrand then
  744.             realScroll[1] = math.min(realScroll[1] + config.workspaceMoveSpeed, scroll[1] + xrand)
  745.             changed = true
  746.         elseif realScroll[1] > scroll[1] + xrand then
  747.             realScroll[1] = math.max(realScroll[1] - config.workspaceMoveSpeed, scroll[1] + xrand)
  748.             changed = true
  749.         end
  750.         if realScroll[2] < scroll[2] + yrand then
  751.             realScroll[2] = math.min(realScroll[2] + config.workspaceMoveSpeed, scroll[2] + yrand)
  752.             changed = true
  753.         elseif realScroll[2] > scroll[2] + yrand then
  754.             realScroll[2] = math.max(realScroll[2] - config.workspaceMoveSpeed, scroll[2] + yrand)
  755.             changed = true
  756.         end
  757.     end
  758.     gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  759.     for y = gridMinY, gridHeight do
  760.         if instances[y] then
  761.             for x = gridMinX, gridWidth do
  762.                 if instances[y][x] then
  763.  
  764.                     instances[y][x].window.x = math.floor(1 + (x + realScroll[1] - 1) * scr_x)
  765.                     instances[y][x].window.y = math.floor(1 + (y + realScroll[2] - 1) * scr_y)
  766.                     if not instances[y][x].paused then
  767.                         tickDownInstanceTimers(x, y)
  768.                     end
  769.  
  770.                 end
  771.             end
  772.         end
  773.     end
  774.     return changed
  775. end
  776.  
  777. local swapInstances = function(xmod, ymod)
  778.     if not instances[focus[2]][focus[1]].active then
  779.         table.insert(instances[focus[2]][focus[1]].extraEvents, {"workspace_swap"})
  780.     end
  781.     if not instances[focus[2] + ymod][focus[1] + xmod].active then
  782.         table.insert(instances[focus[2] + ymod][focus[1] + xmod].extraEvents, {"workspace_swap"})
  783.     end
  784.  
  785.     instances[focus[2]][focus[1]], instances[focus[2] + ymod][focus[1] + xmod] = instances[focus[2] + ymod][focus[1] + xmod], instances[focus[2]][focus[1]]
  786.     instances[focus[2]][focus[1]].x, instances[focus[2] + ymod][focus[1] + xmod].x = instances[focus[2] + ymod][focus[1] + xmod].x, instances[focus[2]][focus[1]].x
  787.     instances[focus[2]][focus[1]].y, instances[focus[2] + ymod][focus[1] + xmod].y = instances[focus[2] + ymod][focus[1] + xmod].y, instances[focus[2]][focus[1]].y
  788. end
  789.  
  790. local addWorkspace = function(xmod, ymod)
  791.     config.WSmap[focus[2] + ymod] = config.WSmap[focus[2] + ymod] or {}
  792.     if not config.WSmap[focus[2] + ymod][focus[1] + xmod] then
  793.         config.WSmap[focus[2] + ymod][focus[1] + xmod] = true
  794.         newInstance(focus[1] + xmod, focus[2] + ymod, config.defaultProgram, false)
  795.         saveConfig()
  796.         gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  797.     end
  798. end
  799.  
  800. local removeWorkspace = function(xmod, ymod)
  801.     if config.WSmap[focus[2] + ymod][focus[1] + xmod] then
  802.         local good = false
  803.  
  804.         for m = 1, math.max(gridHeight - gridMinY + 1, gridWidth - gridMinX + 1) do
  805.             for y = -1, 1 do
  806.                 for x = -1, 1 do
  807.                     if math.abs(x) + math.abs(y) == 1 then
  808.                         if instances[focus[2] + y * m] then
  809.                             if instances[focus[2] + y * m][focus[1] + x * m] then
  810.                                 good = true
  811.                                 break
  812.                             end
  813.                         end
  814.                     end
  815.                 end
  816.                 if good then
  817.                     break
  818.                 end
  819.             end
  820.             if good then
  821.                 break
  822.             end
  823.         end
  824.  
  825.         if good then
  826.             lddterm.windows[instances[focus[2] + ymod][focus[1] + xmod].window.layer] = nil
  827.             config.WSmap[focus[2] + ymod][focus[1] + xmod] = nil
  828.             instances[focus[2] + ymod][focus[1] + xmod] = nil
  829.             local isRowEmpty
  830.             local remList = {}
  831.             for y, v in pairs(config.WSmap) do
  832.                 isRowEmpty = true
  833.                 for x, vv in pairs(v) do
  834.                     if vv then
  835.                         isRowEmpty = false
  836.                         break
  837.                     end
  838.                 end
  839.                 if isRowEmpty then
  840.                     remList[#remList + 1] = y
  841.                 end
  842.             end
  843.             for i = 1, #remList do
  844.                 config.WSmap[remList[i]] = nil
  845.             end
  846.             saveConfig()
  847.             gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  848.         end
  849.     else
  850. --      print("There's no such workspace.")
  851.     end
  852. end
  853.  
  854. local displayHelp = function()
  855.     cwrite("CTRL+SHIFT+ARROW to switch workspace.   ",  -3 + scr_y / 2)
  856.     cwrite("CTRL+SHIFT+TAB+ARROW to swap.           ",  -2 + scr_y / 2)
  857.     cwrite("CTRL+SHIFT+[WASD] to create a workspace ",  -1 + scr_y / 2)
  858.     cwrite(" up/left/down/right respectively.       ",   0 + scr_y / 2)
  859.     cwrite("CTRL+SHIFT+P to pause a workspace.      ",   1 + scr_y / 2)
  860.     cwrite("CTRL+SHIFT+Q to delete a workspace.     ",   2 + scr_y / 2)
  861.     cwrite("Terminate an inactive workspace to exit.",   3 + scr_y / 2)
  862. end
  863.  
  864. local inputEvt = {
  865.     key = true,
  866.     key_up = true,
  867.     char = true,
  868.     mouse_click = true,
  869.     mouse_scroll = true,
  870.     mouse_drag = true,
  871.     mouse_up = true,
  872.     paste = true,
  873.     terminate = true
  874. }
  875.  
  876. local checkIfCanRun = function(evt, x, y)
  877.     return (
  878.         justStarted or (
  879.             (not instances[y][x].paused) and (
  880.                 not instances[y][x].eventFilter or
  881.                 instances[y][x].eventFilter == evt[1] or
  882.                 evt[1] == "terminate"
  883.             ) and (
  884.                 (not inputEvt[evt[1]]) and
  885.                 instances[y][x].active or (
  886.                     x == focus[1] and
  887.                     y == focus[2]
  888.                 ) or (
  889.                     x == focus[1] and
  890.                     y == focus[2]
  891.                 ) and (
  892.                     evt[1] == "terminate"
  893.                 ) or evt[1] == "workspace_swap"
  894.             )
  895.         )
  896.     )
  897. end
  898.  
  899. local main = function()
  900.     local enteringCommand
  901.     local justStarted = true
  902.     local tID, wID = 0, 0
  903.     local pCounter, program = 0
  904.     local oldFuncReplace = {os = {}, term = {}} -- used when replacing certain os functions per-instance
  905.  
  906.     for y, v in pairs(config.WSmap) do
  907.         for x, vv in pairs(v) do
  908.             if vv then
  909.                 pCounter = pCounter + 1
  910.                 program = (argList[pCounter] and fs.exists(argList[pCounter])) and argList[pCounter]
  911.                 if not program then
  912.                     program = (argList[pCounter] and fs.exists(argList[pCounter] .. ".lua")) and (argList[pCounter] .. ".lua")
  913.                 end
  914.                 newInstance(
  915.                     x, y,
  916.                     program or config.defaultProgram,
  917.                     program and true or (pCounter == 1)
  918.                 )
  919.             end
  920.         end
  921.     end
  922.  
  923.     gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  924.     focus[2] = gridMinY
  925.     for x = gridMinX, gridWidth do
  926.         if instances[focus[2]][x] then
  927.             focus[1] = x
  928.             realScroll = {-x + 1, -gridMinY + 1}
  929.             scroll = {-x + 1, -gridMinY + 1}
  930.             break
  931.         end
  932.     end
  933.  
  934.     scrollWindows(true, false)
  935.  
  936.     term.clear()
  937.     if config.timesRan <= 0 then
  938.         displayHelp()
  939.         sleep(0.1)
  940.         os.pullEvent("key")
  941.  
  942.         os.queueEvent("mouse_click", 0, 0, 0)
  943.     end
  944.  
  945.     config.timesRan = config.timesRan + 1
  946.     saveConfig()
  947.  
  948.     local previousTerm, cSuccess
  949.  
  950.     local setInstanceSpecificFunctions = function(x, y)
  951.         os.startTimer = function(duration)
  952.             if type(duration) == "number" then
  953.                 local t
  954.                 while true do
  955.                     t = math.random(1, 2^30)
  956.                     if not instances[y][x].timer[t] then
  957.                         instances[y][x].timer[t] = math.floor(duration * 20) / 20
  958.                         return t
  959.                     end
  960.                 end
  961.             else
  962.                 error("bad argument #1 (number expected, got " .. type(duration) .. ")", 2)
  963.             end
  964.         end
  965.         os.cancelTimer = function(id)
  966.             if type(id) == "number" then
  967.                 instances[y][x].timer[id] = nil
  968.             else
  969.                 error("bad argument #1 (number expected, got " .. type(id) .. ")", 2)
  970.             end
  971.         end
  972.         if config.doPauseClockAndTime then
  973.             os.clock = function()
  974.                 return oldFuncReplace.os.clock() + instances[y][x].clockMod
  975.             end
  976.             os.time = function()
  977.                 return oldFuncReplace.os.time() + instances[y][x].timeMod
  978.             end
  979.         end
  980.         os.queueEvent = function(evt, ...)
  981.             if type(evt) == "string" then
  982.                 instances[y][x].extraEvents[#instances[y][x].extraEvents + 1] = {evt, ...}
  983.             else
  984.                 error("bad argument #1 (number expected, got " .. type(evt) .. ")", 2)
  985.             end
  986.         end
  987.     end
  988.  
  989.     -- timer for instance timers and window scrolling
  990.     tID = os.startTimer(0.05)
  991.  
  992.     -- if true, timer events won't be accepted by instances (unless it's an extraEvent)
  993.     local banTimerEvent, evt
  994.     local doRedraw = false
  995.  
  996.     local checkIfExtraEvents = function()
  997.         for y = gridMinY, gridHeight do
  998.             if instances[y] then
  999.                 for x = gridMinX, gridWidth do
  1000.                     if instances[y][x] then
  1001.                         if #instances[y][x].extraEvents ~= 0 then
  1002.                             return true
  1003.                         end
  1004.                     end
  1005.                 end
  1006.             end
  1007.         end
  1008.         return false
  1009.     end
  1010.  
  1011.     while isRunning do
  1012.         gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1013.         doRedraw = false
  1014.  
  1015.         evt = {os.pullEventRaw()}
  1016.  
  1017.         enteringCommand = false
  1018.         if evt[1] == "key" then
  1019.             keysDown[evt[2]] = true
  1020.         elseif evt[1] == "key_up" then
  1021.             keysDown[evt[2]] = nil
  1022.         elseif evt[1] == "timer" then
  1023.             if evt[2] == wID then
  1024.                 enteringCommand = true
  1025.                 doDrawWorkspaceIndicator = false
  1026.                 banTimerEvent = true
  1027.                 doRedraw = true
  1028.             else
  1029.                 if evt[2] == tID then
  1030.                     doRedraw = true
  1031.                     banTimerEvent = true
  1032.                     tID = os.startTimer(0.05)
  1033.                     scrollWindows(true, true)
  1034.                 else
  1035.                     banTimerEvent = false
  1036.                     scrollWindows(false, true)
  1037.                 end
  1038.             end
  1039.         end
  1040.  
  1041.         if (keysDown[keys.leftCtrl] or keysDown[keys.rightCtrl]) and (keysDown[keys.leftShift] or keysDown[keys.rightShift]) then
  1042.             if evt[1] == "key" then
  1043.                 if evt[2] == keys.p then
  1044.                     if instances[focus[2]][focus[1]].active then
  1045.                         instances[focus[2]][focus[1]].paused = not instances[focus[2]][focus[1]].paused
  1046.                         enteringCommand = true
  1047.                         doDrawWorkspaceIndicator = instances[focus[2]][focus[1]].paused and 2 or 3
  1048.                         os.cancelTimer(wID)
  1049.                         wID = os.startTimer(workspaceIndicatorDuration)
  1050.                         if config.doPauseClockAndTime then
  1051.                             if instances[focus[2]][focus[1]].paused then
  1052.                                 instances[focus[2]][focus[1]].lastClock = os.clock() + instances[focus[2]][focus[1]].clockMod
  1053.                                 instances[focus[2]][focus[1]].lastTime = os.time() + instances[focus[2]][focus[1]].timeMod
  1054.                             else
  1055.                                 instances[focus[2]][focus[1]].clockMod = instances[focus[2]][focus[1]].lastClock - os.clock()
  1056.                                 instances[focus[2]][focus[1]].timeMod = instances[focus[2]][focus[1]].lastTime - os.time()
  1057.                             end
  1058.                         end
  1059.                     end
  1060.                 elseif evt[2] == keys.o then
  1061.                     loadConfig()
  1062.                 end
  1063.             end
  1064.             if keysDown[keys.left] then
  1065.                 for i = 1, (not config.skipAcrossEmptyWorkspaces) and 1 or (focus[1] - gridMinX + 1) do
  1066.                     if instances[focus[2]][focus[1] - i] then
  1067.                         if keysDown[swapKey] then
  1068.                             swapInstances(-i, 0)
  1069.                         end
  1070.                         focus[1] = focus[1] - i
  1071.                         scroll[1] = scroll[1] + i
  1072.                         keysDown[keys.left] = false
  1073.                         break
  1074.                     end
  1075.                 end
  1076.                 doDrawWorkspaceIndicator = 1
  1077.                 os.cancelTimer(wID)
  1078.                 wID = os.startTimer(workspaceIndicatorDuration)
  1079.                 enteringCommand = true
  1080.             end
  1081.             if keysDown[keys.right] then
  1082.                 for i = 1, (not config.skipAcrossEmptyWorkspaces) and 1 or (gridWidth - focus[1]) do
  1083.                     if instances[focus[2]][focus[1] + i] then
  1084.                         if keysDown[swapKey] then
  1085.                             swapInstances(i, 0)
  1086.                         end
  1087.                         focus[1] = focus[1] + i
  1088.                         scroll[1] = scroll[1] - i
  1089.                         keysDown[keys.right] = false
  1090.                         break
  1091.                     end
  1092.                 end
  1093.                 doDrawWorkspaceIndicator = 1
  1094.                 os.cancelTimer(wID)
  1095.                 wID = os.startTimer(workspaceIndicatorDuration)
  1096.                 enteringCommand = true
  1097.             end
  1098.             if keysDown[keys.up] then
  1099.                 for i = 1, (not config.skipAcrossEmptyWorkspaces) and 1 or (focus[2] - gridMinY + 1) do
  1100.                     if instances[focus[2] - i] then
  1101.                         if instances[focus[2] - i][focus[1]] then
  1102.                             if keysDown[swapKey] then
  1103.                                 swapInstances(0, -i)
  1104.                             end
  1105.                             focus[2] = focus[2] - i
  1106.                             scroll[2] = scroll[2] + i
  1107.                             keysDown[keys.up] = false
  1108.                             break
  1109.                         end
  1110.                     end
  1111.                 end
  1112.                 doDrawWorkspaceIndicator = 1
  1113.                 os.cancelTimer(wID)
  1114.                 wID = os.startTimer(workspaceIndicatorDuration)
  1115.                 enteringCommand = true
  1116.             end
  1117.             if keysDown[keys.down] then
  1118.                 for i = 1, (not config.skipAcrossEmptyWorkspaces) and 1 or (gridHeight - focus[2]) do
  1119.                     if instances[focus[2] + i] then
  1120.                         if instances[focus[2] + i][focus[1]] then
  1121.                             if keysDown[swapKey] then
  1122.                                 swapInstances(0, i)
  1123.                             end
  1124.                             focus[2] = focus[2] + i
  1125.                             scroll[2] = scroll[2] - i
  1126.                             keysDown[keys.down] = false
  1127.                             break
  1128.                         end
  1129.                     end
  1130.                 end
  1131.                 doDrawWorkspaceIndicator = 1
  1132.                 os.cancelTimer(wID)
  1133.                 wID = os.startTimer(workspaceIndicatorDuration)
  1134.                 enteringCommand = true
  1135.             end
  1136.             if keysDown[keys.w] then
  1137.                 addWorkspace(0, -1)
  1138.                 doDrawWorkspaceIndicator = 1
  1139.                 os.cancelTimer(wID)
  1140.                 wID = os.startTimer(workspaceIndicatorDuration)
  1141.                 keysDown[keys.w] = false
  1142.                 gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1143.             end
  1144.             if keysDown[keys.s] then
  1145.                 addWorkspace(0, 1)
  1146.                 doDrawWorkspaceIndicator = 1
  1147.                 os.cancelTimer(wID)
  1148.                 wID = os.startTimer(workspaceIndicatorDuration)
  1149.                 keysDown[keys.s] = false
  1150.                 gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1151.             end
  1152.             if keysDown[keys.a] then
  1153.                 addWorkspace(-1, 0)
  1154.                 doDrawWorkspaceIndicator = 1
  1155.                 os.cancelTimer(wID)
  1156.                 wID = os.startTimer(workspaceIndicatorDuration)
  1157.                 keysDown[keys.a] = false
  1158.                 gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1159.             end
  1160.             if keysDown[keys.d] then
  1161.                 addWorkspace(1, 0)
  1162.                 doDrawWorkspaceIndicator = 1
  1163.                 os.cancelTimer(wID)
  1164.                 wID = os.startTimer(workspaceIndicatorDuration)
  1165.                 keysDown[keys.d] = false
  1166.                 gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1167.             end
  1168.             if keysDown[keys.q] then
  1169.                 doDrawWorkspaceIndicator = 1
  1170.                 os.cancelTimer(wID)
  1171.                 wID = os.startTimer(workspaceIndicatorDuration)
  1172.                 keysDown[keys.q] = false
  1173.                 local good = false
  1174.                 for m = 1, math.max(gridHeight - gridMinY + 1, gridWidth - gridMinX + 1) do
  1175.                     for y = -1, 1 do
  1176.                         for x = -1, 1 do
  1177.                             if math.abs(x) + math.abs(y) == 1 then
  1178.                                 if instances[focus[2] + y * m] then
  1179.                                     if instances[focus[2] + y * m][focus[1] + x * m] then
  1180.                                         removeWorkspace(0, 0)
  1181.                                         focus = {
  1182.                                             focus[1] + x * m,
  1183.                                             focus[2] + y * m
  1184.                                         }
  1185.                                         scroll = {
  1186.                                             scroll[1] - x * m,
  1187.                                             scroll[2] - y * m
  1188.                                         }
  1189.                                         good = true
  1190.                                         break
  1191.                                     end
  1192.                                 end
  1193.                             end
  1194.                         end
  1195.                         if good then
  1196.                             break
  1197.                         end
  1198.                     end
  1199.                     if good then
  1200.                         break
  1201.                     end
  1202.                 end
  1203.                 gridWidth, gridHeight, gridMinX, gridMinY = getMapSize()
  1204.             end
  1205.         end
  1206.  
  1207.         if not enteringCommand then
  1208.  
  1209.             oldFuncReplace.os.startTimer = os.startTimer
  1210.             oldFuncReplace.os.cancelTimer = os.cancelTimer
  1211.             if config.doPauseClockAndTime then
  1212.                 oldFuncReplace.os.clock = os.clock
  1213.                 oldFuncReplace.os.time = os.time
  1214.             end
  1215.             oldFuncReplace.os.queueEvent = os.queueEvent
  1216.  
  1217.             for y = gridMinY, gridHeight do
  1218.                 if instances[y] then
  1219.                     for x = gridMinX, gridWidth do
  1220.                         if instances[y][x] then
  1221.  
  1222.                             setInstanceSpecificFunctions(x, y)
  1223.                             previousTerm = term.redirect(instances[y][x].window.handle)
  1224.  
  1225.                             if justStarted or (checkIfCanRun(evt, x, y) and not (banTimerEvent and evt[1] == "timer")) then
  1226.                                 cSuccess, instances[y][x].eventFilter = coroutine.resume(instances[y][x].co, table.unpack(evt))
  1227.                             end
  1228.  
  1229.                             if #instances[y][x].extraEvents ~= 0 and not instances[y][x].paused then
  1230.                                 for i = 1, #instances[y][x].extraEvents do
  1231.                                     if checkIfCanRun(instances[y][x].extraEvents[i], x, y) then
  1232.                                         cSuccess, instances[y][x].eventFilter = coroutine.resume(instances[y][x].co, table.unpack(instances[y][x].extraEvents[i]))
  1233.                                     else
  1234.                                         break
  1235.                                     end
  1236.                                 end
  1237.                                 instances[y][x].extraEvents = {}
  1238.                             end
  1239.  
  1240.                             term.redirect(previousTerm)
  1241.  
  1242.                         end
  1243.                     end
  1244.                 end
  1245.             end
  1246.  
  1247.             os.startTimer = oldFuncReplace.os.startTimer
  1248.             os.cancelTimer = oldFuncReplace.os.cancelTimer
  1249.             if config.doPauseClockAndTime then
  1250.                 os.clock = oldFuncReplace.os.clock
  1251.                 os.time = oldFuncReplace.os.time
  1252.             end
  1253.             os.queueEvent = oldFuncReplace.os.queueEvent
  1254.  
  1255.         end
  1256.  
  1257.         if doRedraw then
  1258.             lddterm.render()
  1259.         end
  1260.  
  1261.         lddterm.selectedWindow = instances[focus[2]][focus[1]].window.layer
  1262.         justStarted = false
  1263.  
  1264.     end
  1265. end
  1266.  
  1267. local function interpretArgs(tInput, tArgs)
  1268.     local output = {}
  1269.     local errors = {}
  1270.     local usedEntries = {}
  1271.     for aName, aType in pairs(tArgs) do
  1272.         output[aName] = false
  1273.         for i = 1, #tInput do
  1274.             if not usedEntries[i] then
  1275.                 if tInput[i] == aName and not output[aName] then
  1276.                     if aType then
  1277.                         usedEntries[i] = true
  1278.                         if type(tInput[i+1]) == aType or type(tonumber(tInput[i+1])) == aType then
  1279.                             usedEntries[i+1] = true
  1280.                             if aType == "number" then
  1281.                                 output[aName] = tonumber(tInput[i+1])
  1282.                             else
  1283.                                 output[aName] = tInput[i+1]
  1284.                             end
  1285.                         else
  1286.                             output[aName] = nil
  1287.                             errors[1] = errors[1] and (errors[1] + 1) or 1
  1288.                             errors[aName] = "expected " .. aType .. ", got " .. type(tInput[i+1])
  1289.                         end
  1290.                     else
  1291.                         usedEntries[i] = true
  1292.                         output[aName] = true
  1293.                     end
  1294.                 end
  1295.             end
  1296.         end
  1297.     end
  1298.     for i = 1, #tInput do
  1299.         if not usedEntries[i] then
  1300.             output[#output+1] = tInput[i]
  1301.         end
  1302.     end
  1303.     return output, errors
  1304. end
  1305.  
  1306. local argData = {
  1307.     ["--help"] = false,
  1308.     ["-h"] = false,
  1309.     ["--config"] = false,
  1310.     ["-c"] = false
  1311. }
  1312.  
  1313. argList, argErrors = interpretArgs({...}, argData)
  1314.  
  1315. if argList["--help"] or argList["-h"] then
  1316.     displayHelp()
  1317.     write("\n")
  1318.     return
  1319. elseif argList["--config"] or argList["-c"] then
  1320.     shell.run("rom/programs/edit.lua", configPath)
  1321.     return
  1322. end
  1323.  
  1324. if _G.currentlyRunningWorkspace then
  1325.     print("Workspace is already running.")
  1326.     return
  1327. else
  1328.     _G.currentlyRunningWorkspace = true
  1329. end
  1330.  
  1331. _G.instances = instances
  1332.  
  1333. local result, message = pcall(main)
  1334.  
  1335. _G.currentlyRunningWorkspace = false
  1336.  
  1337. term.clear()
  1338. term.setCursorPos(1,1)
  1339. if result then
  1340.     print("Thanks for using Workspace!")
  1341. else
  1342.     print("There was an error, and Workspace had to stop.")
  1343.     print("The error goes as follows:\n")
  1344.     print(message)
  1345. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement