Advertisement
MAG_Gen

LZSSEPM (LZSS self-extracting program maker) Installer

Sep 23rd, 2023 (edited)
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 40.85 KB | Source Code | 0 0
  1. --backup color
  2. local fg,bg=term.getTextColor(),term.getBackgroundColor()
  3. --init file locals
  4. local file1,st_file
  5. local lzssepm_code=[===[-- LZSS SEP-Maker
  6. --
  7. -- This program was made to create self-extracting archives.
  8. --
  9. -- That kind of self-extracting programs(SEP) has built-in LZSS
  10. -- unpack function, so they can be launched without LZSS installed.
  11. -- You can run them with pastebin or wget or directly from
  12. -- shell (or.run is posible but unrecomended)
  13.  
  14. -- Help message
  15. local tArgs={...}
  16. if not ... then print"Usage: <src> [dest] [wget] [uneffective] [rewrite]"return end
  17.  
  18. --main part (part that will be inserted at the start of file)
  19. local extractor_base=[==[P=P:sub(SiZ,ZiS)while#P>=o do f=P:byte(o)o=o+1
  20. for _=0,7 do s=nil
  21. if 0<A(f,1)then
  22. if#P>=o then s=S(P,o,o)o=o+1
  23. end
  24. elseif#P>=o+1 then
  25. t=('>I2'):unpack(P,o)p=1+R(t,4)s=S(w,p,p+A(t,15)+2)o=o+2
  26. end
  27. f=R(f,1)if s then w=S(w..s,-4096)r=r..s end
  28. end
  29. end
  30. return load(r,O,nil,_ENV)(...)--[]==]
  31.  
  32. --advanced extractor (biger then default, but can be launched directly from wget/pastebin)
  33. local extractor_wget=[==[local D,A,R,o,r,w,f,t,p,s,S,O,G,L,P=debug or{},bit32.band,bit32.rshift,1,'',''G=D.getinfo or r.char
  34. L=D.getlocal
  35. O=(G(3)or{}).source or""P=O:find"wget.lua$"and 4 or O:find"pastebin.lua$"and 6 or P
  36. S=O.sub
  37. if P then D,O=L(3,P)D,P=L(3,7)else L=shell O=L and"@/"..L.resolveProgram(arg[0])or(G(1)or{}).source or""D,L=io.open(S(O,2),'rb')L=L and error(L)P=D:read"*a"D:close()end
  38. ]==]
  39.  
  40. --default extractor (can start from file only, but smaller)
  41. local extractor_def =[==[local D,A,R,L,o,r,w,f,t,p,s,S,O,P=debug or{},bit32.band,bit32.rshift,shell,1,'',''S=r.sub
  42. O=L and"@/"..L.resolveProgram(arg[0])or(D.getinfo or r.char)(1).source or""D,L=io.open(S(O,2),'rb')L=L and error(L)P=D:read"*a"D:close()]==]
  43. -- "@/" - needed to make chunknames of packed programs similar to unpacked ones
  44.  
  45. -- read source
  46. local eq_count=0
  47. local file=fs.open(...or"",'r') or error"LZSS> Can't open source file..."
  48. local before=file.readAll()
  49. local prog=lzss.pack(before)
  50. file.close()
  51.  
  52. -- choose/print extractor
  53. local wget
  54. write"LZSSEPM> Add wget/pastebin support? [Y/n]: "
  55. if tArgs[3]=="true"or tArgs[3]=="Y"or tArgs[3]=="y"then print(tArgs[3]) wget=1
  56. elseif tArgs[3]=="false" or tArgs[3]=="N"or tArgs[3]=="n" then print(tArgs[3])
  57. else
  58.     wget = read():find"^[Yy]"
  59. end
  60. print("LZSSEPM> Extractor type :",wget and"WGET/PASTEBIN Support"or"Default")
  61. local extractor = (wget and extractor_wget or extractor_def)..extractor_base
  62. print(("LZSSEPM> Extractor size : %.2f"):format(#extractor/1024),"Kb's\n")
  63.  
  64. -- make container for compressed code
  65. k=false
  66. repeat
  67.     if prog:find('([%[%]])'..("="):rep(eq_count)..'%1') then
  68.         eq_count=eq_count+1
  69.     else
  70.         k=true
  71.     end
  72. until k
  73.  
  74. --print stats
  75. print(("LZSSEPM> Default size   : %.2f"):format(#before/1024),"Kb's")
  76. print(("LZSSEPM> After LZSS size: %.2f"):format(#prog/1024),"Kb's")
  77. print(("LZSSEPM> Final size     : %.2f"):format((#prog+#extractor+3+eq_count*2)/1024),"Kb's\n")
  78.  
  79. --Warning if compression is bad
  80. if #before <= #prog+#extractor+3+eq_count*2 then
  81.     print"LZSSEPM> Ineffective compression!"
  82.     write"LZSSEPM> Continue? [Y/n]: "
  83.     if tArgs[4]=="false"or tArgs[4]=="N" or tArgs[4]=="n"then print(tArgs[4])return
  84.     elseif tArgs[4]=="true"or tArgs[4]=="Y" or tArgs[4]=="y"then print(tArgs[4])
  85.     elseif read():find"^[^Yy]" then return
  86.     end
  87.     print()
  88. end
  89.  
  90. -- set dest file
  91. local dest = tArgs[2] or ... .. ".sep"
  92. if fs.exists(dest) then
  93.     print"LZSSEPM> Destination already exists!"
  94.     write"LZSSEPM> Continue? [Y/n]: "
  95.     if tArgs[5]=="true"or tArgs[5]=="Y"or tArgs[5]=="y"then print(tArgs[5])
  96.     elseif tArgs[5]=="false"or tArgs[5]=="N"or tArgs[5]=="n"then print(tArgs[5])return
  97.     elseif read():find"^[^Yy]"then return
  98.     end
  99. end
  100.  
  101. -- write dest file
  102. file=fs.open(dest,'wb')
  103. file.write(extractor:gsub("SiZ",#extractor+2+eq_count):gsub("ZiS",("%.2d"):format(-3-eq_count)))--extractior
  104. file.write(("="):rep(eq_count).."["..prog.."]"..("="):rep(eq_count).."]")--code
  105. file.close()
  106. print("LZSSEPM> Packing complete:",dest)]===]
  107.  
  108. local startup_code=[===[local path,comp,fl,ch="PATH_R",require"cc.shell.completion"
  109. fl={comp.file,true}
  110. ch={comp.choice,{"true ","false "}}
  111. shell.setAlias("lzssepm",path)
  112. shell.setCompletionFunction(path,comp.build(fl,fl,ch,ch,ch))]===]
  113.  
  114. --Install function
  115. local install = function(lzssepm_path,lzssepm,startup)
  116.     startup_code=startup_code:gsub("PATH_R",fs.combine(lzssepm_path))
  117.     lzssepm.write(lzssepm_code)--make prog
  118.     startup.write(startup_code)--make startup
  119. end
  120.  
  121. --QUITE RUN
  122. --Args: -lzss=*path_to_lzssepm_path* --startup=*startup_file* --func
  123.  
  124. if #{...}>0 then --quite run
  125.     local type_api="Minified LZSS"
  126.     local path_to_lzssepm
  127.     local path_to_startup
  128.     local install_prog=false
  129.     for _,k in pairs{...}do --for all args
  130.         if k:find"^%-S=" or k:find"^%-%-startup=" then --install startup (path to startup)
  131.             path_to_startup=k:match"=(.+)$"
  132.             print("LZSSEPM> startup:",path_to_startup)
  133.         elseif k:find"^%-P" or k:find"^%-%-program" then --install the LZSS shell Launcher (simple archiver with size of 598 bytes
  134.             install_prog=true
  135.             print("LZSSEPM> prog:",path_to_lzssepm)
  136.         elseif k:find"^%-H" or k:find"^%-%-help" then
  137.             print("Usage:\n"..
  138.                   "  lzssepm_install *no_args* --launch UI\n"..
  139.                   "\n"..
  140.                   "  -H --help --Show this message and exit\n"..
  141.                   "  -S=*path* --startup=*path*\n"..
  142.                   "        --Set the path to startup file\n"..
  143.                   "  -P --program=*path*\n"..
  144.                   "        --Set the path to program file")
  145.             return
  146.         else
  147.             error("Unexpected argument: "..k)
  148.         end
  149.     end
  150.     if not path_to_lzssepm then error"Path to instalation file not set! Use <-P=*path_to_file*> or <--prog=*path_to_file*>.\nP.S:(You can launch lzssepm_install with no args to use GUI)"end
  151.     local tmp1,err1=fs.open(fs.combine(path_to_lzssepm),"w")
  152.     file1=tmp1 or error(err1)
  153.     if not path_to_lzssepm then error"Path to startup file not set! Use <-S=*path_to_file*> or <--startup=*path_to_file*>.\nP.S:(You can launch lzssepm_install with no args to use GUI)"end
  154.     local tmp3,err3=fs.open(path_to_startup,"w")
  155.     st_file=tmp3 or error(err3)
  156.     install(path_to_lzssepm,file1,st_file)
  157.     print("LZSSEPM> Instalation complete...")
  158.     print("LZSSEPM> Please reload OS...")
  159. else --no args - interface launch required
  160.  
  161. ------------------------------------------------------------------------------------
  162. ------------------------------------------------------------------------------------
  163. ------------------------------------------------------------------------------------
  164. --PrimeUI INIT SECTION (This part of code was created by JackMacWindows)
  165. local expect = require "cc.expect".expect
  166.  
  167. -- Initialization code
  168. local PrimeUI = {}
  169. do
  170.     local coros = {}
  171.     local restoreCursor
  172.  
  173.     --- Adds a task to run in the main loop.
  174.     ---@param func function The function to run, usually an `os.pullEvent` loop
  175.     function PrimeUI.addTask(func)
  176.         expect(1, func, "function")
  177.         local t = {coro = coroutine.create(func)}
  178.         coros[#coros+1] = t
  179.         _, t.filter = coroutine.resume(t.coro)
  180.     end
  181.  
  182.     --- Sends the provided arguments to the run loop, where they will be returned.
  183.     ---@param ... any The parameters to send
  184.     function PrimeUI.resolve(...)
  185.         coroutine.yield(coros, ...)
  186.     end
  187.  
  188.     --- Clears the screen and resets all components. Do not use any previously
  189.     --- created components after calling this function.
  190.     function PrimeUI.clear()
  191.         -- Reset the screen.
  192.         term.setCursorPos(1, 1)
  193.         term.setCursorBlink(false)
  194.         term.setBackgroundColor(colors.black)
  195.         term.setTextColor(colors.white)
  196.         term.clear()
  197.         -- Reset the task list and cursor restore function.
  198.         coros = {}
  199.         restoreCursor = nil
  200.     end
  201.  
  202.     --- Sets or clears the window that holds where the cursor should be.
  203.     ---@param win window|nil The window to set as the active window
  204.     function PrimeUI.setCursorWindow(win)
  205.         expect(1, win, "table", "nil")
  206.         restoreCursor = win and win.restoreCursor
  207.     end
  208.  
  209.     --- Gets the absolute position of a coordinate relative to a window.
  210.     ---@param win window The window to check
  211.     ---@param x number The relative X position of the point
  212.     ---@param y number The relative Y position of the point
  213.     ---@return number x The absolute X position of the window
  214.     ---@return number y The absolute Y position of the window
  215.     function PrimeUI.getWindowPos(win, x, y)
  216.         if win == term then return x, y end
  217.         while win ~= term.native() and win ~= term.current() do
  218.             if not win.getPosition then return x, y end
  219.             local wx, wy = win.getPosition()
  220.             x, y = x + wx - 1, y + wy - 1
  221.             _, win = debug.getupvalue(select(2, debug.getupvalue(win.isColor, 1)), 1) -- gets the parent window through an upvalue
  222.         end
  223.         return x, y
  224.     end
  225.  
  226.     --- Runs the main loop, returning information on an action.
  227.     ---@return any ... The result of the coroutine that exited
  228.     function PrimeUI.run()
  229.         while true do
  230.             -- Restore the cursor and wait for the next event.
  231.             if restoreCursor then restoreCursor() end
  232.             local ev = table.pack(os.pullEvent())
  233.             -- Run all coroutines.
  234.             for _, v in ipairs(coros) do
  235.                 if v.filter == nil or v.filter == ev[1] then
  236.                     -- Resume the coroutine, passing the current event.
  237.                     local res = table.pack(coroutine.resume(v.coro, table.unpack(ev, 1, ev.n)))
  238.                     -- If the call failed, bail out. Coroutines should never exit.
  239.                     if not res[1] then error(res[2], 2) end
  240.                     -- If the coroutine resolved, return its values.
  241.                     if res[2] == coros then return table.unpack(res, 3, res.n) end
  242.                     -- Set the next event filter.
  243.                     v.filter = res[2]
  244.                 end
  245.             end
  246.         end
  247.     end
  248. end
  249.  
  250. --- Draws a line of text at a position.
  251. ---@param win window The window to draw on
  252. ---@param x number The X position of the left side of the text
  253. ---@param y number The Y position of the text
  254. ---@param text string The text to draw
  255. ---@param fgColor color|nil The color of the text (defaults to white)
  256. ---@param bgColor color|nil The color of the background (defaults to black)
  257. function PrimeUI.label(win, x, y, text, fgColor, bgColor)
  258.     expect(1, win, "table")
  259.     expect(2, x, "number")
  260.     expect(3, y, "number")
  261.     expect(4, text, "string")
  262.     fgColor = expect(5, fgColor, "number", "nil") or colors.white
  263.     bgColor = expect(6, bgColor, "number", "nil") or colors.black
  264.     win.setCursorPos(x, y)
  265.     win.setTextColor(fgColor)
  266.     win.setBackgroundColor(bgColor)
  267.     win.write(text)
  268. end
  269.  
  270. --- Draws a horizontal line at a position with the specified width.
  271. ---@param win window The window to draw on
  272. ---@param x number The X position of the left side of the line
  273. ---@param y number The Y position of the line
  274. ---@param width number The width/length of the line
  275. ---@param fgColor color|nil The color of the line (defaults to white)
  276. ---@param bgColor color|nil The color of the background (defaults to black)
  277. function PrimeUI.horizontalLine(win, x, y, width, fgColor, bgColor)
  278.     expect(1, win, "table")
  279.     expect(2, x, "number")
  280.     expect(3, y, "number")
  281.     expect(4, width, "number")
  282.     fgColor = expect(5, fgColor, "number", "nil") or colors.white
  283.     bgColor = expect(6, bgColor, "number", "nil") or colors.black
  284.     -- Use drawing characters to draw a thin line.
  285.     win.setCursorPos(x, y)
  286.     win.setTextColor(fgColor)
  287.     win.setBackgroundColor(bgColor)
  288.     win.write(("\x8C"):rep(width))
  289. end
  290.  
  291. --- Creates a clickable button on screen with text.
  292. ---@param win window The window to draw on
  293. ---@param x number The X position of the button
  294. ---@param y number The Y position of the button
  295. ---@param text string The text to draw on the button
  296. ---@param action function|string A function to call when clicked, or a string to send with a `run` event
  297. ---@param fgColor color|nil The color of the button text (defaults to white)
  298. ---@param bgColor color|nil The color of the button (defaults to light gray)
  299. ---@param clickedColor color|nil The color of the button when clicked (defaults to gray)
  300. function PrimeUI.button(win, x, y, text, action, fgColor, bgColor, clickedColor)
  301.     expect(1, win, "table")
  302.     expect(2, x, "number")
  303.     expect(3, y, "number")
  304.     expect(4, text, "string")
  305.     expect(5, action, "function", "string")
  306.     fgColor = expect(6, fgColor, "number", "nil") or colors.white
  307.     bgColor = expect(7, bgColor, "number", "nil") or colors.gray
  308.     clickedColor = expect(8, clickedColor, "number", "nil") or colors.lightGray
  309.     -- Draw the initial button.
  310.     win.setCursorPos(x, y)
  311.     win.setBackgroundColor(bgColor)
  312.     win.setTextColor(fgColor)
  313.     win.write(" " .. text .. " ")
  314.     -- Get the screen position and add a click handler.
  315.     PrimeUI.addTask(function()
  316.         local buttonDown = false
  317.         while true do
  318.             local event, button, clickX, clickY = os.pullEvent()
  319.             local screenX, screenY = PrimeUI.getWindowPos(win, x, y)
  320.             if event == "mouse_click" and button == 1 and clickX >= screenX and clickX < screenX + #text + 2 and clickY == screenY then
  321.                 -- Initiate a click action (but don't trigger until mouse up).
  322.                 buttonDown = true
  323.                 -- Redraw the button with the clicked background color.
  324.                 win.setCursorPos(x, y)
  325.                 win.setBackgroundColor(clickedColor)
  326.                 win.setTextColor(fgColor)
  327.                 win.write(" " .. text .. " ")
  328.             elseif event == "mouse_up" and button == 1 and buttonDown then
  329.                 -- Finish a click event.
  330.                 if clickX >= screenX and clickX < screenX + #text + 2 and clickY == screenY then
  331.                     -- Trigger the action.
  332.                     if type(action) == "string" then PrimeUI.resolve("button", action)
  333.                     else action() end
  334.                 end
  335.                 -- Redraw the original button state.
  336.                 win.setCursorPos(x, y)
  337.                 win.setBackgroundColor(bgColor)
  338.                 win.setTextColor(fgColor)
  339.                 win.write(" " .. text .. " ")
  340.             end
  341.         end
  342.     end)
  343. end
  344.  
  345. --- Adds an action to trigger when a key is pressed.
  346. ---@param key key The key to trigger on, from `keys.*`
  347. ---@param action function|string A function to call when clicked, or a string to use as a key for a `run` return event
  348. function PrimeUI.keyAction(key, action)
  349.     expect(1, key, "number")
  350.     expect(2, action, "function", "string")
  351.     PrimeUI.addTask(function()
  352.         while true do
  353.             local _, param1 = os.pullEvent("key") -- wait for key
  354.             if param1 == key then
  355.                 if type(action) == "string" then PrimeUI.resolve("keyAction", action)
  356.                 else action() end
  357.             end
  358.         end
  359.     end)
  360. end
  361.  
  362. --- Adds an action to trigger when a key is pressed with modifier keys.
  363. ---@param key key The key to trigger on, from `keys.*`
  364. ---@param withCtrl boolean Whether Ctrl is required
  365. ---@param withAlt boolean Whether Alt is required
  366. ---@param withShift boolean Whether Shift is required
  367. ---@param action function|string A function to call when clicked, or a string to use as a key for a `run` return event
  368. function PrimeUI.keyCombo(key, withCtrl, withAlt, withShift, action)
  369.     expect(1, key, "number")
  370.     expect(2, withCtrl, "boolean")
  371.     expect(3, withAlt, "boolean")
  372.     expect(4, withShift, "boolean")
  373.     expect(5, action, "function", "string")
  374.     PrimeUI.addTask(function()
  375.         local heldCtrl, heldAlt, heldShift = false, false, false
  376.         while true do
  377.             local event, param1, param2 = os.pullEvent() -- wait for key
  378.             if event == "key" then
  379.                 -- check if key is down, all modifiers are correct, and that it's not held
  380.                 if param1 == key and heldCtrl == withCtrl and heldAlt == withAlt and heldShift == withShift and not param2 then
  381.                     if type(action) == "string" then PrimeUI.resolve("keyCombo", action)
  382.                     else action() end
  383.                 -- activate modifier keys
  384.                 elseif param1 == keys.leftCtrl or param1 == keys.rightCtrl then heldCtrl = true
  385.                 elseif param1 == keys.leftAlt or param1 == keys.rightAlt then heldAlt = true
  386.                 elseif param1 == keys.leftShift or param1 == keys.rightShift then heldShift = true end
  387.             elseif event == "key_up" then
  388.                 -- deactivate modifier keys
  389.                 if param1 == keys.leftCtrl or param1 == keys.rightCtrl then heldCtrl = false
  390.                 elseif param1 == keys.leftAlt or param1 == keys.rightAlt then heldAlt = false
  391.                 elseif param1 == keys.leftShift or param1 == keys.rightShift then heldShift = false end
  392.             end
  393.         end
  394.     end)
  395. end
  396.  
  397. --- Creates a scrollable window, which allows drawing large content in a small area.
  398. ---@param win window The parent window of the scroll box
  399. ---@param x number The X position of the box
  400. ---@param y number The Y position of the box
  401. ---@param width number The width of the box
  402. ---@param height number The height of the outer box
  403. ---@param innerHeight number The height of the inner scroll area
  404. ---@param allowArrowKeys boolean|nil Whether to allow arrow keys to scroll the box (defaults to true)
  405. ---@param showScrollIndicators boolean|nil Whether to show arrow indicators on the right side when scrolling is available, which reduces the inner width by 1 (defaults to false)
  406. ---@param fgColor number|nil The color of scroll indicators (defaults to white)
  407. ---@param bgColor color|nil The color of the background (defaults to black)
  408. ---@return window inner The inner window to draw inside
  409. function PrimeUI.scrollBox(win, x, y, width, height, innerHeight, allowArrowKeys, showScrollIndicators, fgColor, bgColor)
  410.     expect(1, win, "table")
  411.     expect(2, x, "number")
  412.     expect(3, y, "number")
  413.     expect(4, width, "number")
  414.     expect(5, height, "number")
  415.     expect(6, innerHeight, "number")
  416.     expect(7, allowArrowKeys, "boolean", "nil")
  417.     expect(8, showScrollIndicators, "boolean", "nil")
  418.     fgColor = expect(9, fgColor, "number", "nil") or colors.white
  419.     bgColor = expect(10, bgColor, "number", "nil") or colors.black
  420.     if allowArrowKeys == nil then allowArrowKeys = true end
  421.     -- Create the outer container box.
  422.     local outer = window.create(win == term and term.current() or win, x, y, width, height)
  423.     outer.setBackgroundColor(bgColor)
  424.     outer.clear()
  425.     -- Create the inner scrolling box.
  426.     local inner = window.create(outer, 1, 1, width - (showScrollIndicators and 1 or 0), innerHeight)
  427.     inner.setBackgroundColor(bgColor)
  428.     inner.clear()
  429.     -- Draw scroll indicators if desired.
  430.     if showScrollIndicators then
  431.         outer.setBackgroundColor(bgColor)
  432.         outer.setTextColor(fgColor)
  433.         outer.setCursorPos(width, height)
  434.         outer.write(innerHeight > height and "\31" or " ")
  435.     end
  436.     -- Get the absolute position of the window.
  437.     x, y = PrimeUI.getWindowPos(win, x, y)
  438.     -- Add the scroll handler.
  439.     PrimeUI.addTask(function()
  440.         local scrollPos = 1
  441.         while true do
  442.             -- Wait for next event.
  443.             local ev = table.pack(os.pullEvent())
  444.             -- Update inner height in case it changed.
  445.             innerHeight = select(2, inner.getSize())
  446.             -- Check for scroll events and set direction.
  447.             local dir
  448.             if ev[1] == "key" and allowArrowKeys then
  449.                 if ev[2] == keys.up then dir = -1
  450.                 elseif ev[2] == keys.down then dir = 1 end
  451.             elseif ev[1] == "mouse_scroll" and ev[3] >= x and ev[3] < x + width and ev[4] >= y and ev[4] < y + height then
  452.                 dir = ev[2]
  453.             end
  454.             -- If there's a scroll event, move the window vertically.
  455.             if dir and (scrollPos + dir >= 1 and scrollPos + dir <= innerHeight - height) then
  456.                 scrollPos = scrollPos + dir
  457.                 inner.reposition(1, 2 - scrollPos)
  458.             end
  459.             -- Redraw scroll indicators if desired.
  460.             if showScrollIndicators then
  461.                 outer.setBackgroundColor(bgColor)
  462.                 outer.setTextColor(fgColor)
  463.                 outer.setCursorPos(width, 1)
  464.                 outer.write(scrollPos > 1 and "\30" or " ")
  465.                 outer.setCursorPos(width, height)
  466.                 outer.write(scrollPos < innerHeight - height and "\31" or " ")
  467.             end
  468.         end
  469.     end)
  470.     return inner
  471. end
  472.  
  473. --- Creates a text input box.
  474. ---@param win window The window to draw on
  475. ---@param x number The X position of the left side of the box
  476. ---@param y number The Y position of the box
  477. ---@param width number The width/length of the box
  478. ---@param action function|string A function or `run` event to call when the enter key is pressed
  479. ---@param fgColor color|nil The color of the text (defaults to white)
  480. ---@param bgColor color|nil The color of the background (defaults to black)
  481. ---@param replacement string|nil A character to replace typed characters with
  482. ---@param history string[]|nil A list of previous entries to provide
  483. ---@param completion function|nil A function to call to provide completion
  484. ---@param default string|nil A string to return if the box is empty
  485. function PrimeUI.inputBox(win, x, y, width, action, fgColor, bgColor, replacement, history, completion, default)
  486.     expect(1, win, "table")
  487.     expect(2, x, "number")
  488.     expect(3, y, "number")
  489.     expect(4, width, "number")
  490.     expect(5, action, "function", "string")
  491.     fgColor = expect(6, fgColor, "number", "nil") or colors.white
  492.     bgColor = expect(7, bgColor, "number", "nil") or colors.black
  493.     expect(8, replacement, "string", "nil")
  494.     expect(9, history, "table", "nil")
  495.     expect(10, completion, "function", "nil")
  496.     expect(11, default, "string", "nil")
  497.     -- Create a window to draw the input in.
  498.     local box = window.create(win, x, y, width, 1)
  499.     box.setTextColor(fgColor)
  500.     box.setBackgroundColor(bgColor)
  501.     box.clear()
  502.     -- Call read() in a new coroutine.
  503.     PrimeUI.addTask(function()
  504.         -- We need a child coroutine to be able to redirect back to the window.
  505.         local coro = coroutine.create(read)
  506.         -- Run the function for the first time, redirecting to the window.
  507.         local old = term.redirect(box)
  508.         local ok, res = coroutine.resume(coro, replacement, history, completion, default)
  509.         term.redirect(old)
  510.         -- Run the coroutine until it finishes.
  511.         while coroutine.status(coro) ~= "dead" do
  512.             -- Get the next event.
  513.             local ev = table.pack(os.pullEvent())
  514.             -- Redirect and resume.
  515.             old = term.redirect(box)
  516.             ok, res = coroutine.resume(coro, table.unpack(ev, 1, ev.n))
  517.             term.redirect(old)
  518.             -- Pass any errors along.
  519.             if not ok then error(res) end
  520.         end
  521.         -- Send the result to the receiver.
  522.         if type(action) == "string" then PrimeUI.resolve("inputBox", action, res)
  523.         else action(res) end
  524.         -- Spin forever, because tasks cannot exit.
  525.         while true do os.pullEvent() end
  526.     end)
  527. end
  528.  
  529. --- Creates a list of entries with toggleable check boxes.
  530. ---@param win window The window to draw on
  531. ---@param x number The X coordinate of the inside of the box
  532. ---@param y number The Y coordinate of the inside of the box
  533. ---@param width number The width of the inner box
  534. ---@param height number The height of the inner box
  535. ---@param selections {string: string|boolean} A list of entries to show, where the value is whether the item is pre-selected (or `"R"` for required/forced selected)
  536. ---@param action function|string|nil A function or `run` event that's called when a selection is made
  537. ---@param fgColor color|nil The color of the text (defaults to white)
  538. ---@param bgColor color|nil The color of the background (defaults to black)
  539. function PrimeUI.checkSelectionBox(win, x, y, width, height, selections, action, fgColor, bgColor)
  540.     expect(1, win, "table")
  541.     expect(2, x, "number")
  542.     expect(3, y, "number")
  543.     expect(4, width, "number")
  544.     expect(5, height, "number")
  545.     expect(6, selections, "table")
  546.     expect(7, action, "function", "string", "nil")
  547.     fgColor = expect(8, fgColor, "number", "nil") or colors.white
  548.     bgColor = expect(9, bgColor, "number", "nil") or colors.black
  549.     -- Calculate how many selections there are.
  550.     local nsel = 0
  551.     for _ in pairs(selections) do nsel = nsel + 1 end
  552.     -- Create the outer display box.
  553.     local outer = window.create(win, x, y, width, height)
  554.     outer.setBackgroundColor(bgColor)
  555.     outer.clear()
  556.     -- Create the inner scroll box.
  557.     local inner = window.create(outer, 1, 1, width - 1, nsel)
  558.     inner.setBackgroundColor(bgColor)
  559.     inner.setTextColor(fgColor)
  560.     inner.clear()
  561.     -- Draw each line in the window.
  562.     local lines = {}
  563.     local nl, selected = 1, 1
  564.     for k, v in pairs(selections) do
  565.         inner.setCursorPos(1, nl)
  566.         inner.write((v and (v == "R" and "[-] " or "[\xD7] ") or "[ ] ") .. k)
  567.         lines[nl] = {k, not not v}
  568.         nl = nl + 1
  569.     end
  570.     -- Draw a scroll arrow if there is scrolling.
  571.     if nsel > height then
  572.         outer.setCursorPos(width, height)
  573.         outer.setBackgroundColor(bgColor)
  574.         outer.setTextColor(fgColor)
  575.         outer.write("\31")
  576.     end
  577.     -- Set cursor blink status.
  578.     inner.setCursorPos(2, selected)
  579.     inner.setCursorBlink(true)
  580.     PrimeUI.setCursorWindow(inner)
  581.     -- Get screen coordinates & add run task.
  582.     local screenX, screenY = PrimeUI.getWindowPos(win, x, y)
  583.     PrimeUI.addTask(function()
  584.         local scrollPos = 1
  585.         while true do
  586.             -- Wait for an event.
  587.             local ev = table.pack(os.pullEvent())
  588.             -- Look for a scroll event or a selection event.
  589.             local dir
  590.             if ev[1] == "key" then
  591.                 if ev[2] == keys.up then dir = -1
  592.                 elseif ev[2] == keys.down then dir = 1
  593.                 elseif ev[2] == keys.space and selections[lines[selected][1]] ~= "R" then
  594.                     -- (Un)select the item.
  595.                     lines[selected][2] = not lines[selected][2]
  596.                     inner.setCursorPos(2, selected)
  597.                     inner.write(lines[selected][2] and "\xD7" or " ")
  598.                     -- Call the action if passed; otherwise, set the original table.
  599.                     if type(action) == "string" then PrimeUI.resolve("checkSelectionBox", action, lines[selected][1], lines[selected][2])
  600.                     elseif action then action(lines[selected][1], lines[selected][2])
  601.                     else selections[lines[selected][1]] = lines[selected][2] end
  602.                     -- Redraw all lines in case of changes.
  603.                     for i, v in ipairs(lines) do
  604.                         local vv = selections[v[1]] == "R" and "R" or v[2]
  605.                         inner.setCursorPos(2, i)
  606.                         inner.write((vv and (vv == "R" and "-" or "\xD7") or " "))
  607.                     end
  608.                     inner.setCursorPos(2, selected)
  609.                 end
  610.             elseif ev[1] == "mouse_scroll" and ev[3] >= screenX and ev[3] < screenX + width and ev[4] >= screenY and ev[4] < screenY + height then
  611.                 dir = ev[2]
  612.             end
  613.             -- Scroll the screen if required.
  614.             if dir and (selected + dir >= 1 and selected + dir <= nsel) then
  615.                 selected = selected + dir
  616.                 if selected - scrollPos < 0 or selected - scrollPos >= height then
  617.                     scrollPos = scrollPos + dir
  618.                     inner.reposition(1, 2 - scrollPos)
  619.                 end
  620.                 inner.setCursorPos(2, selected)
  621.             end
  622.             -- Redraw scroll arrows and reset cursor.
  623.             outer.setCursorPos(width, 1)
  624.             outer.write(scrollPos > 1 and "\30" or " ")
  625.             outer.setCursorPos(width, height)
  626.             outer.write(scrollPos < nsel - height + 1 and "\31" or " ")
  627.             inner.restoreCursor()
  628.         end
  629.     end)
  630. end
  631.  
  632. --- Creates a text box that wraps text and can have its text modified later.
  633. ---@param win window The parent window of the text box
  634. ---@param x number The X position of the box
  635. ---@param y number The Y position of the box
  636. ---@param width number The width of the box
  637. ---@param height number The height of the box
  638. ---@param text string The initial text to draw
  639. ---@param fgColor color|nil The color of the text (defaults to white)
  640. ---@param bgColor color|nil The color of the background (defaults to black)
  641. ---@return function redraw A function to redraw the window with new contents
  642. function PrimeUI.textBox(win, x, y, width, height, text, fgColor, bgColor)
  643.     expect(1, win, "table")
  644.     expect(2, x, "number")
  645.     expect(3, y, "number")
  646.     expect(4, width, "number")
  647.     expect(5, height, "number")
  648.     expect(6, text, "string")
  649.     fgColor = expect(7, fgColor, "number", "nil") or colors.white
  650.     bgColor = expect(8, bgColor, "number", "nil") or colors.black
  651.     -- Create the box window.
  652.     local box = window.create(win, x, y, width, height)
  653.     -- Override box.getSize to make print not scroll.
  654.     function box.getSize()
  655.         return width, math.huge
  656.     end
  657.     -- Define a function to redraw with.
  658.     local function redraw(_text)
  659.         expect(1, _text, "string")
  660.         -- Set window parameters.
  661.         box.setBackgroundColor(bgColor)
  662.         box.setTextColor(fgColor)
  663.         box.clear()
  664.         box.setCursorPos(1, 1)
  665.         -- Redirect and draw with `print`.
  666.         local old = term.redirect(box)
  667.         print(_text)
  668.         term.redirect(old)
  669.     end
  670.     redraw(text)
  671.     return redraw
  672. end
  673.  
  674. --- Draws a thin border around a screen region.
  675. ---@param win window The window to draw on
  676. ---@param x number The X coordinate of the inside of the box
  677. ---@param y number The Y coordinate of the inside of the box
  678. ---@param width number The width of the inner box
  679. ---@param height number The height of the inner box
  680. ---@param fgColor color|nil The color of the border (defaults to white)
  681. ---@param bgColor color|nil The color of the background (defaults to black)
  682. function PrimeUI.borderBox(win, x, y, width, height, fgColor, bgColor)
  683.     expect(1, win, "table")
  684.     expect(2, x, "number")
  685.     expect(3, y, "number")
  686.     expect(4, width, "number")
  687.     expect(5, height, "number")
  688.     fgColor = expect(6, fgColor, "number", "nil") or colors.white
  689.     bgColor = expect(7, bgColor, "number", "nil") or colors.black
  690.     -- Draw the top-left corner & top border.
  691.     win.setBackgroundColor(bgColor)
  692.     win.setTextColor(fgColor)
  693.     win.setCursorPos(x - 1, y - 1)
  694.     win.write("\x9C" .. ("\x8C"):rep(width))
  695.     -- Draw the top-right corner.
  696.     win.setBackgroundColor(fgColor)
  697.     win.setTextColor(bgColor)
  698.     win.write("\x93")
  699.     -- Draw the right border.
  700.     for i = 1, height do
  701.         win.setCursorPos(win.getCursorPos() - 1, y + i - 1)
  702.         win.write("\x95")
  703.     end
  704.     -- Draw the left border.
  705.     win.setBackgroundColor(bgColor)
  706.     win.setTextColor(fgColor)
  707.     for i = 1, height do
  708.         win.setCursorPos(x - 1, y + i - 1)
  709.         win.write("\x95")
  710.     end
  711.     -- Draw the bottom border and corners.
  712.     win.setCursorPos(x - 1, y + height)
  713.     win.write("\x8D" .. ("\x8C"):rep(width) .. "\x8E")
  714. end
  715.  
  716. --- Draws a block of text inside a window with word wrapping, optionally resizing the window to fit.
  717. ---@param win window The window to draw in
  718. ---@param text string The text to draw
  719. ---@param resizeToFit boolean|nil Whether to resize the window to fit the text (defaults to false). This is useful for scroll boxes.
  720. ---@param fgColor color|nil The color of the text (defaults to white)
  721. ---@param bgColor color|nil The color of the background (defaults to black)
  722. ---@return number lines The total number of lines drawn
  723. function PrimeUI.drawText(win, text, resizeToFit, fgColor, bgColor)
  724.     expect(1, win, "table")
  725.     expect(2, text, "string")
  726.     expect(3, resizeToFit, "boolean", "nil")
  727.     fgColor = expect(4, fgColor, "number", "nil") or colors.white
  728.     bgColor = expect(5, bgColor, "number", "nil") or colors.black
  729.     -- Set colors.
  730.     win.setBackgroundColor(bgColor)
  731.     win.setTextColor(fgColor)
  732.     -- Redirect to the window to use print on it.
  733.     local old = term.redirect(win)
  734.     -- Draw the text using print().
  735.     local lines = print(text)
  736.     -- Redirect back to the original terminal.
  737.     term.redirect(old)
  738.     -- Resize the window if desired.
  739.     if resizeToFit then
  740.         -- Get original parameters.
  741.         local x, y = win.getPosition()
  742.         local w = win.getSize()
  743.         -- Resize the window.
  744.         win.reposition(x, y, w, lines)
  745.     end
  746.     return lines
  747. end
  748.  
  749. --- Runs a function or action after the specified time period, with optional canceling.
  750. ---@param time number The amount of time to wait for, in seconds
  751. ---@param action function|string The function to call when the timer completes, or a `run` event to send
  752. ---@return function cancel A function to cancel the timer
  753. function PrimeUI.timeout(time, action)
  754.     expect(1, time, "number")
  755.     expect(2, action, "function", "string")
  756.     -- Start the timer.
  757.     local timer = os.startTimer(time)
  758.     -- Add a task to wait for the timer.
  759.     PrimeUI.addTask(function()
  760.         while true do
  761.             -- Wait for a timer event.
  762.             local _, tm = os.pullEvent("timer")
  763.             if tm == timer then
  764.                 -- Fire the timer action.
  765.                 if type(action) == "string" then PrimeUI.resolve("timeout", action)
  766.                 else action() end
  767.             end
  768.         end
  769.     end)
  770.     -- Return a function to cancel the timer.
  771.     return function() os.cancelTimer(timer) end
  772. end
  773.  
  774. --PrimeUI INIT END
  775. ------------------------------------------------------------------------------------
  776. ------------------------------------------------------------------------------------
  777. ------------------------------------------------------------------------------------
  778.  
  779.  
  780. local comp=require"cc.shell.completion"
  781. local main=term.current()
  782. x,y=6,10
  783. max_x,max_y=term.getSize()
  784.  
  785. local desc1=[[--PACKAGE DESCRIPTION--
  786.  
  787. This package has quiet install mode.
  788. Use `-H` or `--help` option for more information.
  789.  
  790. Controls:
  791.  Enter  == Continue
  792.  Ctrl+c == Exit / Cancel
  793.  Space  == Select option
  794.  
  795. Package version: 1.0
  796. Package creator: M.A.G.Gen.
  797. Git: https://github.com/MAGGen-hub
  798.  
  799. PrimeUI creator: JackMacWindows
  800. Git: https://github.com/MCJack123/PrimeUI
  801.  
  802. ALL LICENCES ARE PUBLIC:
  803. For a more detailed acquaintance visit previously mentioned links.
  804.  
  805. WARNING!
  806.  This package require default LZSS package!
  807.  To install it run `pastebin run MxnRb6E8`
  808.  Required modules: Minified API; startup module.
  809.  
  810. WARNING!
  811.  This package has no minified version.
  812.  If you have size issues and can't install it
  813. Use LZSSEPM-Online:
  814.  `pastebin run 35C8TNCZ`
  815.  
  816. What is lzssepm.lua?
  817. lzssepm.lua - program for making self-extracting programs (SEP).
  818. SEP usualy have smaller size than default program.
  819. SEP's has built-in unpack function from LZSS archiver.
  820. Lzssepm was created to provide transparent compression to your programs, so user of SEP's can launch them without LZSS package instalation.
  821.  
  822. WARNING!
  823. It's nice if you have only one or two SEP's on your system, but if you have a lot of them - installing LZSS will be much more efficient solution!
  824.  
  825. --END OF PACKAGE DESCRIPTION--
  826. ]]
  827.  
  828. mkgui=function(nobtn)
  829.    local lab="LZSSEPM Installer V1.0"
  830.    PrimeUI.label(main,3,2,lab,colors.yellow)
  831.    PrimeUI.horizontalLine(main,3,3,#lab + 2,colors.yellow)
  832.    PrimeUI.borderBox(main,4,6,max_x-x,max_y-y,colors.yellow)
  833.    PrimeUI.keyCombo(keys.c,true,false,false,"exit")
  834.    if not nobtn then
  835.        PrimeUI.keyAction(keys.enter,"done")
  836.        PrimeUI.button(main,3,max_y-2,"Continue","done",colors.yellow,nil,colors.lightGray)
  837.        PrimeUI.button(main,14,max_y-2,"Cancel","exit",colors.yellow,nil,colors.lightGray)
  838.    else
  839.        PrimeUI.label(main,3,max_y-2," Continue ",colors.lightGray,colors.gray)
  840.        PrimeUI.button(main,14,max_y-2,"Cancel","exit",colors.yellow,nil,colors.lightGray)
  841.    end
  842. end
  843.  
  844. --DESCRIPTION SHOW--
  845. PrimeUI.clear()
  846. mkgui()
  847. local scroll_box=PrimeUI.scrollBox(main,4,6,max_x-x, max_y-y,999,true,true)
  848. PrimeUI.drawText(scroll_box,desc1,true)
  849. local _,act = PrimeUI.run()
  850.  
  851. local lzssepm_path,prev,err
  852. --SELECT LZSSEPM FOLDER
  853. if act=="done" then
  854.    local histor={"/lzssepm.lua","/progs/lzssepm.lua","/programs/lzssepm.lua","/disk/lzssepm.lua","/lib/lzssepm.lua","/apis/lzssepm.lua","/lzss/lzssepm.lua"}-- posible names for directory
  855.    --wnd.reposition(4,9)
  856.    --wnd.clear()
  857.    repeat
  858.        lzssepm_path=nil
  859.        PrimeUI.clear()
  860.        mkgui(true)
  861.        PrimeUI.label(main,4,6,"Choose instalation file (use \x12):",colors.yellow)
  862.        paintutils.drawLine(4,8,max_x-x+3,8,colors.gray)
  863.        PrimeUI.inputBox(main,5,8,max_x-x-2,"done",colors.yellow,colors.gray,nil,histor,
  864.            function(sLine) if #sLine>0 then return comp.dir(shell,sLine)end end,histor[#histor])
  865.        
  866.        PrimeUI.textBox(main,4,9,max_x-x,3,err or"",colors.red)
  867.        _,act,lzssepm_path=PrimeUI.run()--attempt to get the way
  868.        _,err=pcall(function()
  869.            if lzssepm_path then --create files if posible
  870.                if prev~=lzssepm_path and fs.exists(lzssepm_path) then
  871.                    prev=lzssepm_path
  872.                    error("Warning! File 'lzssepm.lua' will be rewriten! Are you sure? [Enter]"..prev..tostring(prev~=lzssepm_path))
  873.                end
  874.                local tmp1,err1=fs.open(fs.combine(lzssepm_path),"w")
  875.                err1=tmp1 or error(err1)
  876.                file1=tmp1
  877.            end
  878.        end)
  879.        histor[#histor+1]=lzssepm_path~=histor[#histor] and lzssepm_path or nil
  880.        
  881.    until file1 or act=="exit"
  882. end
  883.  
  884. err=nil
  885. local st_path
  886. --SELECT STARTUP
  887. if act=="done" then
  888.    local histor={"/startup.lua","/disk/startup.lua","/disk/startup/01_lzssepm.lua","/startup/lzssepm.lua","/startup/02_lzssepm.lua","/startup/01_lzssepm.lua"}
  889.    repeat
  890.        PrimeUI.clear()
  891.        mkgui(true)
  892.        PrimeUI.label(main,4,6,"Enter startup (use \x12):",colors.yellow)
  893.        paintutils.drawLine(4,8,max_x-x+3,8,colors.gray)
  894.        PrimeUI.inputBox(main,5,8,max_x-x-2,"done",colors.yellow,colors.gray,nil,histor,
  895.            function(sLine) if #sLine>0 then return comp.dirOrFile(shell,sLine)end end, histor[#histor])
  896.        PrimeUI.textBox(main,4,9,max_x-x,3,err or"",colors.red)
  897.        _,act,st_path=PrimeUI.run()
  898.        _,err=pcall(function()
  899.                if st_path then
  900.                    local tmp,err1=fs.open(st_path,"w")
  901.                    st_file=tmp or error(err1)
  902.                end
  903.            end)
  904.        histor[#histor+1]=st_path~=histor[#histor] and st_path or nil
  905.    until st_file or act=="exit"
  906. end
  907.  
  908. --SIZE DEMO PART
  909. if act=="done" then
  910.    local s_prog = #lzssepm_code/1024 or 0
  911.    local s_stp =(#startup_code - 6 + #lzssepm_path)/1024
  912.    PrimeUI.clear()
  913.    mkgui()
  914.    PrimeUI.label(main ,4,6,("Startup:   %6.2fKb's"):format(s_stp),colors.yellow)
  915.    PrimeUI.label(main ,4,7,("   Prog:   %6.2fKb's"):format(s_prog),colors.yellow)
  916.    PrimeUI.label(main ,4,8,("Total Size:%6.2fKb's"):format(s_prog+s_stp),colors.yellow)
  917.    PrimeUI.label(main ,4,9,"Continue instalation?",colors.yellow)
  918.    _,act=PrimeUI.run()
  919. end
  920.  
  921. --INSTALL PART
  922. if act=="done" then
  923.    install(lzssepm_path,file1,st_file)
  924.    PrimeUI.clear()
  925.    mkgui()
  926.    PrimeUI.label(main ,4,6,"Instalation completed...",colors.yellow)
  927.    PrimeUI.label(main ,4,7,"Please reload OS...",colors.yellow)
  928.    PrimeUI.label(main ,4,8,"Press any key to continue...",colors.yellow)
  929.    PrimeUI.label(main ,4,9,"Program will exit automaticly after 5 seconds.",colors.yellow)
  930.    PrimeUI.addTask(function()while true do
  931.        local ev=os.pullEvent"key"
  932.        ev=ev and PrimeUI.resolve()
  933.        end
  934.    end)
  935.    PrimeUI.timeout(5,"done")
  936.    PrimeUI.run()
  937. end
  938.  
  939. --IF CANCELED
  940. if act=="exit" then
  941.    PrimeUI.clear()
  942.    mkgui()
  943.    PrimeUI.label(main ,4,6,"Instalation canceled. Press any key to exit.",colors.red)
  944.    PrimeUI.label(main ,4,7,"Program will exit automaticly after 3 seconds.",colors.yellow)
  945.    PrimeUI.addTask(function()while true do
  946.        local ev=os.pullEvent"key"
  947.        ev=ev and PrimeUI.resolve()
  948.        end
  949.    end)
  950.    PrimeUI.timeout(3,"done")
  951.    PrimeUI.run()
  952. end
  953. end
  954.  
  955. --close all files
  956. _=file1 and pcall(file1.close)
  957. _=st_file and pcall(st_file.close)
  958. if #{...}<1 then
  959.   --restore color after UI and clear shell
  960.   term.setTextColor(fg) term.setBackgroundColor(bg)
  961.   shell.run"clear"
  962. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement