Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --backup color
- local fg,bg=term.getTextColor(),term.getBackgroundColor()
- --init file locals
- local file1,file2,st_file
- local lzss_api={
- ["Original LZSS"]=[===[ --[[----------------------------------------------------------------------------
- LZSS - encoder / decoder
- This is free and unencumbered software released into the public domain.
- Anyone is free to copy, modify, publish, use, compile, sell, or
- distribute this software, either in source code form or as a compiled
- binary, for any purpose, commercial or non-commercial, and by any
- means.
- In jurisdictions that recognize copyright laws, the author or authors
- of this software dedicate any and all copyright interest in the
- software to the public domain. We make this dedication for the benefit
- of the public at large and to the detriment of our heirs and
- successors. We intend this dedication to be an overt act of
- relinquishment in perpetuity of all present and future rights to this
- software under copyright law.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
- For more information, please refer to <http://unlicense.org/>
- --]] --------------------------------------------------------------------------------------------------------------------------------------------------------
- local M = {}
- local string, table = string, table
- ------------------------------------------------------------------------------
- local POS_BITS = 12
- local LEN_BITS = 16 - POS_BITS
- local POS_SIZE = bit32.lshift(1,POS_BITS)
- local LEN_SIZE = bit32.lshift(1,LEN_BITS)
- local LEN_MIN = 3
- ------------------------------------------------------------------------------
- function M.pack(input)
- local offset, output = 1, {}
- local window = ''
- local function search()
- for i = LEN_SIZE + LEN_MIN - 1, LEN_MIN, -1 do
- local str = string.sub(input, offset, offset + i - 1)
- local pos = string.find(window, str, 1, true)
- if pos then
- return pos, str
- end
- end
- end
- while offset <= #input do
- local flags, buffer = 0, {}
- for i = 0, 7 do
- if offset <= #input then
- local pos, str = search()
- if pos and #str >= LEN_MIN then
- local tmp = bit32.bor(bit32.lshift(pos-1,LEN_BITS), #str - LEN_MIN)
- buffer[#buffer + 1] = string.pack('>I2', tmp)
- else
- flags = bit32.bor(flags,bit32.lshift(1,i))
- str = string.sub(input, offset, offset)
- buffer[#buffer + 1] = str
- end
- window = string.sub(window .. str, -POS_SIZE)
- offset = offset + #str
- else
- break
- end
- end
- if #buffer > 0 then
- output[#output + 1] = string.char(flags)
- output[#output + 1] = table.concat(buffer)
- end
- end
- return table.concat(output)
- end
- ------------------------------------------------------------------------------
- function l_unpack(input)
- local offset, output = 1, {}
- local window = ''
- while offset <= #input do
- local flags = string.byte(input, offset)
- offset = offset + 1
- for i = 1, 8 do
- local str = nil
- if bit32.band(flags,1) ~= 0 then
- if offset <= #input then
- str = string.sub(input, offset, offset)
- offset = offset + 1
- end
- else
- if offset + 1 <= #input then
- local tmp = string.unpack('>I2', input, offset)
- offset = offset + 2
- local pos = bit32.rshift(tmp,LEN_BITS) + 1
- local len = bit32.band(tmp,LEN_SIZE - 1) + LEN_MIN
- str = string.sub(window, pos, pos + len - 1)
- end
- end
- flags = bit32.rshift(flags,1)
- if str then
- output[#output + 1] = str
- window = string.sub(window .. str, -POS_SIZE)
- end
- end
- end
- return table.concat(output)
- end
- M.unpack=l_unpack
- ------------------------------------------------------------------------------
- function M.unpackfile(filename) -- my own function to unpack files fast
- local file, err, str = fs.open(filename,'rb')
- str = file and file.readAll() or error(err)
- file.close()
- return l_unpack(str:gsub("#!lzss\n","",1))
- end
- _G.lzss=M]===],
- --Minified
- ["Minified LZSS"]=[==[U=function(I)local o,r,w,f,t,p,s=1,'',''while#I>=o do f=I:byte(o)o=o+1
- for _=0,7 do s=nil
- if 0<A(f,1)then
- if#I>=o then s=S(I,o,o)o=o+1
- end
- elseif#I>=o+1 then
- t=F:unpack(I,o)p=1+R(t,4)s=S(w,p,p+A(t,15)+2)o=o+2
- end
- f=R(f,1)if s then w=S(w..s,C)r=r..s end
- end
- end
- return r
- end
- _G.lzss={pack=function(I)local L,o,r,w,f,b,s,p=B.lshift,1,'',''while#I>=o do
- f,b=0,''for i=0,7 do
- if#I>=o then
- for j=17,2,-1 do
- s=S(I,o,o+j)p=w:find(s,1,1)if p then break end
- end
- if p and#s>=3 then
- b=b..F:pack(B.bor(L(p-1,4),#s-3))else
- f=B.bor(f,L(1,i))s=S(I,o,o)b=b..s
- end
- w=S(w..s,C)o=o+#s
- else
- break
- end
- end
- if#b>0 then
- r=r..r.char(f)..b
- end
- end
- return r
- end,unpack=U,unpackfile=function(N)local f,e,s=fs.open(N,'rb')
- s=f and f.readAll()or error(e)f.close()return U(s:gsub("#!lzss\n","",1))end}F='>I2'B=bit32
- A=B.band
- R=B.rshift
- S=F.sub
- C=-4^6]==],
- ["LZSS Unpack-Only"]=[==[U=function(I)local o,r,w,f,t,p,s=1,'',''while#I>=o do f=I:byte(o)o=o+1
- for _=0,7 do s=nil
- if 0<A(f,1)then
- if#I>=o then s=S(I,o,o)o=o+1
- end
- elseif#I>=o+1 then
- t=F:unpack(I,o)p=1+R(t,4)s=S(w,p,p+A(t,15)+2)o=o+2
- end
- f=R(f,1)if s then w=S(w..s,C)r=r..s end
- end
- end
- return r
- end
- _G.lzss={unpack=U,unpackfile=function(N)local f,e,s=fs.open(N,'rb')
- s=f and f.readAll()or error(e)f.close()return U(s:gsub("#!lzss\n","",1))end}F='>I2'B=bit32
- A=B.band
- R=B.rshift
- S=F.sub
- C=-4^6]==]}
- local lzss_prog_code=[=[local F,I,O,a,E,C,X,D,P,o,t,R,T,H,f,_,e=...,0,0,{...},error,fs.combine,fs.exists,fs.isDir,print,fs.open,{unpack=".unlzss",pack=".lzss"},'run','true','#!lzss\n't=t[F]f=F==R
- if#a<2 or f then F=f and a[2]or F if F and X(F)then I,O=load(lzss.unpackfile(F),"@"..F,_,_ENV)return(I or E(O))(select(f and 3 or 2,...))end
- P"Usage: lzss <act> <src> [dest] [rewrite] [hashbang]"else
- e=t and lzss[F]or E"Unknown action!"_=C(a[2])f=X(_)or E"No matching files!"R=a[3]or#t<6 and(_:find"%.unlzss"and _:sub(1,-8)or _..t)or _:find"%.lzss"and _:sub(1,-6)or _..t
- f=R and(X(R)and T~=a[4]or fs.isReadOnly(R))and E('Destination "'..R..'" exist or read-only!')f=function(a,s,d,h)if D(s)then
- fs.makeDir(d)for _,v in pairs(fs.list(s))do f(a,C(s,v),C(d,v))end
- else
- F,e=o(s,'rb')s=F and F.readAll():gsub('^'..H,"")or E(e)F.close()F,e=o(d,'wb')_=F or E(e)_=h..a(s)I=I+#s O=O+#_ F.write(_)F.close()end
- end
- f(e,_,R,(T~=a[5]or#t>6)and""or H)P(("In: %.2f Kb's\nOut:%.2f Kb's"):format(I/1024,O/1024))end]=]
- --Install function
- local install = function(lzss_path,type_api,lzss_prog,api,startup)
- lzss_path=lzss_path:find"/$" and lzss_path or lzss_path.."/"
- lzss_path=lzss_path:find"^/" and lzss_path:sub(2,-1) or lzss_path
- if startup then
- local startup_code=""
- if lzss_prog then
- local locals="local p,l,a,c,d,t='"..lzss_path:gsub("'","\'").."','lzss.lua','lzss_api.lua',require'cc.shell.completion'd,t={c.dirOrFile,true},{c.choice,{'true','false'}}shell.run(p..a)"
- local prog=[[shell.setAlias('lzss',p..l)shell.setCompletionFunction(p..l,c.build({c.choice,{"pack ","unpack ","run "}},d,d,t,t))]]
- startup_code=locals..prog
- else
- startup_code="shell.run('"..lzss_path:gsub("'","\'").."lzss_api.lua')"
- end
- startup.write(startup_code)--make startup
- end
- if lzss_prog then
- lzss_prog.write(lzss_prog_code)--make prog
- end
- api.write(lzss_api[type_api])--make api
- end
- --QUITE RUN
- --Args: -lzss=*path_to_lzss_folder* --startup=*startup_file* --func
- if #{...}>0 then --quite run
- local type_api="Minified LZSS"
- local path_to_lzss
- local path_to_startup
- local install_prog=false
- for _,k in pairs{...}do --for all args
- if k:find"^%-L=" or k:find"^%-%-lzss=" then -- path to lzss
- path_to_lzss=k:match"=(.+)$"
- print("LZSS> path:",path_to_lzss)
- elseif k:find"^%-S=" or k:find"^%-%-startup=" then --install startup (path to startup)
- path_to_startup=k:match"=(.+)$"
- print("LZSS> startup:",path_to_startup)
- elseif k:find"^%-O" or k:find"^%-%-original" then --install original unminified LZSS
- type_api="Original LZSS"
- print("LZSS> API:",type_api)
- elseif k:find"^%-U" or k:find"^%-%-unpack%-only" then --install unpack function only (UNRECOMENDED!)
- type_api="LZSS Unpack-Only"
- print("LZSS> API:",type_api)
- elseif k:find"^%-P" or k:find"^%-%-program" then --install the LZSS shell Launcher (simple archiver with size of 598 bytes
- install_prog=true
- print("LZSS> launcher: enabled")
- elseif k:find"^%-M" or k:find"^%-%-minified" then --install the minified LZSS version
- type_api="Minified LZSS"
- print("LZSS> API:",type_api)
- elseif k:find"^%-H" or k:find"^%-%-help" then
- print("Usage:\n"..
- " lzss_install *no_args* --launch UI\n"..
- "\n"..
- " -H --help --Show this message and exit\n"..
- " -L=*path* --lzss=*path*\n"..
- " --Set path to installation folder\n"..
- " -S=*path* --startup=*path*\n"..
- " --Enable startup and set the name of startup file\n"..
- " -P --program\n"..
- " --Enable launching LZSS from shell\n"..
- " -U --unpack-only\n"..
- " --Set API version to unpack-only (UNRECOMENDED)\n"..
- " -M --minified\n"..
- " --Set API version to minified (default, recomended)\n"..
- " -O --original\n"..
- " --Set API version to original (license included)")
- return
- else
- error("Unexpected argument: "..k)
- end
- end
- if not path_to_lzss then error"Path to instalation directory not set! Use <-L=*path_to_dir*> or <--lzss=*path_to_dir*>.\nP.S:(You can launch lzss_install with no args to use GUI)"end
- print("\nLZSS> API:",fs.combine(path_to_lzss,"lzss_api.lua"))
- local tmp1,err1=fs.open(fs.combine(path_to_lzss,"lzss_api.lua"),"w")
- file2=tmp1 or error(err1)
- if install_prog then
- print("LZSS> launcher:",fs.combine(path_to_lzss,"lzss.lua"))
- local tmp2,err2=fs.open(fs.combine(path_to_lzss,"lzss.lua"),"w")
- file1=tmp2 or error(err2)
- end
- if path_to_startup then
- local tmp3,err3=fs.open(path_to_startup,"w")
- st_file=tmp3 or error(err3)
- end
- install(path_to_lzss, type_api ,file1 ,file2 , st_file)
- print("LZSS> Instalation complete...")
- print("LZSS> Please reload OS...")
- else --no args - interface launch required
- ------------------------------------------------------------------------------------
- ------------------------------------------------------------------------------------
- ------------------------------------------------------------------------------------
- --PrimeUI INIT SECTION (This part of code was created by JackMacWindows)
- local expect = require "cc.expect".expect
- -- Initialization code
- local PrimeUI = {}
- do
- local coros = {}
- local restoreCursor
- --- Adds a task to run in the main loop.
- ---@param func function The function to run, usually an `os.pullEvent` loop
- function PrimeUI.addTask(func)
- expect(1, func, "function")
- local t = {coro = coroutine.create(func)}
- coros[#coros+1] = t
- _, t.filter = coroutine.resume(t.coro)
- end
- --- Sends the provided arguments to the run loop, where they will be returned.
- ---@param ... any The parameters to send
- function PrimeUI.resolve(...)
- coroutine.yield(coros, ...)
- end
- --- Clears the screen and resets all components. Do not use any previously
- --- created components after calling this function.
- function PrimeUI.clear()
- -- Reset the screen.
- term.setCursorPos(1, 1)
- term.setCursorBlink(false)
- term.setBackgroundColor(colors.black)
- term.setTextColor(colors.white)
- term.clear()
- -- Reset the task list and cursor restore function.
- coros = {}
- restoreCursor = nil
- end
- --- Sets or clears the window that holds where the cursor should be.
- ---@param win window|nil The window to set as the active window
- function PrimeUI.setCursorWindow(win)
- expect(1, win, "table", "nil")
- restoreCursor = win and win.restoreCursor
- end
- --- Gets the absolute position of a coordinate relative to a window.
- ---@param win window The window to check
- ---@param x number The relative X position of the point
- ---@param y number The relative Y position of the point
- ---@return number x The absolute X position of the window
- ---@return number y The absolute Y position of the window
- function PrimeUI.getWindowPos(win, x, y)
- if win == term then return x, y end
- while win ~= term.native() and win ~= term.current() do
- if not win.getPosition then return x, y end
- local wx, wy = win.getPosition()
- x, y = x + wx - 1, y + wy - 1
- _, win = debug.getupvalue(select(2, debug.getupvalue(win.isColor, 1)), 1) -- gets the parent window through an upvalue
- end
- return x, y
- end
- --- Runs the main loop, returning information on an action.
- ---@return any ... The result of the coroutine that exited
- function PrimeUI.run()
- while true do
- -- Restore the cursor and wait for the next event.
- if restoreCursor then restoreCursor() end
- local ev = table.pack(os.pullEvent())
- -- Run all coroutines.
- for _, v in ipairs(coros) do
- if v.filter == nil or v.filter == ev[1] then
- -- Resume the coroutine, passing the current event.
- local res = table.pack(coroutine.resume(v.coro, table.unpack(ev, 1, ev.n)))
- -- If the call failed, bail out. Coroutines should never exit.
- if not res[1] then error(res[2], 2) end
- -- If the coroutine resolved, return its values.
- if res[2] == coros then return table.unpack(res, 3, res.n) end
- -- Set the next event filter.
- v.filter = res[2]
- end
- end
- end
- end
- end
- --- Draws a line of text at a position.
- ---@param win window The window to draw on
- ---@param x number The X position of the left side of the text
- ---@param y number The Y position of the text
- ---@param text string The text to draw
- ---@param fgColor color|nil The color of the text (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- function PrimeUI.label(win, x, y, text, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, text, "string")
- fgColor = expect(5, fgColor, "number", "nil") or colors.white
- bgColor = expect(6, bgColor, "number", "nil") or colors.black
- win.setCursorPos(x, y)
- win.setTextColor(fgColor)
- win.setBackgroundColor(bgColor)
- win.write(text)
- end
- --- Draws a horizontal line at a position with the specified width.
- ---@param win window The window to draw on
- ---@param x number The X position of the left side of the line
- ---@param y number The Y position of the line
- ---@param width number The width/length of the line
- ---@param fgColor color|nil The color of the line (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- function PrimeUI.horizontalLine(win, x, y, width, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- fgColor = expect(5, fgColor, "number", "nil") or colors.white
- bgColor = expect(6, bgColor, "number", "nil") or colors.black
- -- Use drawing characters to draw a thin line.
- win.setCursorPos(x, y)
- win.setTextColor(fgColor)
- win.setBackgroundColor(bgColor)
- win.write(("\x8C"):rep(width))
- end
- --- Creates a clickable button on screen with text.
- ---@param win window The window to draw on
- ---@param x number The X position of the button
- ---@param y number The Y position of the button
- ---@param text string The text to draw on the button
- ---@param action function|string A function to call when clicked, or a string to send with a `run` event
- ---@param fgColor color|nil The color of the button text (defaults to white)
- ---@param bgColor color|nil The color of the button (defaults to light gray)
- ---@param clickedColor color|nil The color of the button when clicked (defaults to gray)
- function PrimeUI.button(win, x, y, text, action, fgColor, bgColor, clickedColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, text, "string")
- expect(5, action, "function", "string")
- fgColor = expect(6, fgColor, "number", "nil") or colors.white
- bgColor = expect(7, bgColor, "number", "nil") or colors.gray
- clickedColor = expect(8, clickedColor, "number", "nil") or colors.lightGray
- -- Draw the initial button.
- win.setCursorPos(x, y)
- win.setBackgroundColor(bgColor)
- win.setTextColor(fgColor)
- win.write(" " .. text .. " ")
- -- Get the screen position and add a click handler.
- PrimeUI.addTask(function()
- local buttonDown = false
- while true do
- local event, button, clickX, clickY = os.pullEvent()
- local screenX, screenY = PrimeUI.getWindowPos(win, x, y)
- if event == "mouse_click" and button == 1 and clickX >= screenX and clickX < screenX + #text + 2 and clickY == screenY then
- -- Initiate a click action (but don't trigger until mouse up).
- buttonDown = true
- -- Redraw the button with the clicked background color.
- win.setCursorPos(x, y)
- win.setBackgroundColor(clickedColor)
- win.setTextColor(fgColor)
- win.write(" " .. text .. " ")
- elseif event == "mouse_up" and button == 1 and buttonDown then
- -- Finish a click event.
- if clickX >= screenX and clickX < screenX + #text + 2 and clickY == screenY then
- -- Trigger the action.
- if type(action) == "string" then PrimeUI.resolve("button", action)
- else action() end
- end
- -- Redraw the original button state.
- win.setCursorPos(x, y)
- win.setBackgroundColor(bgColor)
- win.setTextColor(fgColor)
- win.write(" " .. text .. " ")
- end
- end
- end)
- end
- --- Adds an action to trigger when a key is pressed.
- ---@param key key The key to trigger on, from `keys.*`
- ---@param action function|string A function to call when clicked, or a string to use as a key for a `run` return event
- function PrimeUI.keyAction(key, action)
- expect(1, key, "number")
- expect(2, action, "function", "string")
- PrimeUI.addTask(function()
- while true do
- local _, param1 = os.pullEvent("key") -- wait for key
- if param1 == key then
- if type(action) == "string" then PrimeUI.resolve("keyAction", action)
- else action() end
- end
- end
- end)
- end
- --- Adds an action to trigger when a key is pressed with modifier keys.
- ---@param key key The key to trigger on, from `keys.*`
- ---@param withCtrl boolean Whether Ctrl is required
- ---@param withAlt boolean Whether Alt is required
- ---@param withShift boolean Whether Shift is required
- ---@param action function|string A function to call when clicked, or a string to use as a key for a `run` return event
- function PrimeUI.keyCombo(key, withCtrl, withAlt, withShift, action)
- expect(1, key, "number")
- expect(2, withCtrl, "boolean")
- expect(3, withAlt, "boolean")
- expect(4, withShift, "boolean")
- expect(5, action, "function", "string")
- PrimeUI.addTask(function()
- local heldCtrl, heldAlt, heldShift = false, false, false
- while true do
- local event, param1, param2 = os.pullEvent() -- wait for key
- if event == "key" then
- -- check if key is down, all modifiers are correct, and that it's not held
- if param1 == key and heldCtrl == withCtrl and heldAlt == withAlt and heldShift == withShift and not param2 then
- if type(action) == "string" then PrimeUI.resolve("keyCombo", action)
- else action() end
- -- activate modifier keys
- elseif param1 == keys.leftCtrl or param1 == keys.rightCtrl then heldCtrl = true
- elseif param1 == keys.leftAlt or param1 == keys.rightAlt then heldAlt = true
- elseif param1 == keys.leftShift or param1 == keys.rightShift then heldShift = true end
- elseif event == "key_up" then
- -- deactivate modifier keys
- if param1 == keys.leftCtrl or param1 == keys.rightCtrl then heldCtrl = false
- elseif param1 == keys.leftAlt or param1 == keys.rightAlt then heldAlt = false
- elseif param1 == keys.leftShift or param1 == keys.rightShift then heldShift = false end
- end
- end
- end)
- end
- --- Creates a scrollable window, which allows drawing large content in a small area.
- ---@param win window The parent window of the scroll box
- ---@param x number The X position of the box
- ---@param y number The Y position of the box
- ---@param width number The width of the box
- ---@param height number The height of the outer box
- ---@param innerHeight number The height of the inner scroll area
- ---@param allowArrowKeys boolean|nil Whether to allow arrow keys to scroll the box (defaults to true)
- ---@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)
- ---@param fgColor number|nil The color of scroll indicators (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- ---@return window inner The inner window to draw inside
- function PrimeUI.scrollBox(win, x, y, width, height, innerHeight, allowArrowKeys, showScrollIndicators, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- expect(5, height, "number")
- expect(6, innerHeight, "number")
- expect(7, allowArrowKeys, "boolean", "nil")
- expect(8, showScrollIndicators, "boolean", "nil")
- fgColor = expect(9, fgColor, "number", "nil") or colors.white
- bgColor = expect(10, bgColor, "number", "nil") or colors.black
- if allowArrowKeys == nil then allowArrowKeys = true end
- -- Create the outer container box.
- local outer = window.create(win == term and term.current() or win, x, y, width, height)
- outer.setBackgroundColor(bgColor)
- outer.clear()
- -- Create the inner scrolling box.
- local inner = window.create(outer, 1, 1, width - (showScrollIndicators and 1 or 0), innerHeight)
- inner.setBackgroundColor(bgColor)
- inner.clear()
- -- Draw scroll indicators if desired.
- if showScrollIndicators then
- outer.setBackgroundColor(bgColor)
- outer.setTextColor(fgColor)
- outer.setCursorPos(width, height)
- outer.write(innerHeight > height and "\31" or " ")
- end
- -- Get the absolute position of the window.
- x, y = PrimeUI.getWindowPos(win, x, y)
- -- Add the scroll handler.
- PrimeUI.addTask(function()
- local scrollPos = 1
- while true do
- -- Wait for next event.
- local ev = table.pack(os.pullEvent())
- -- Update inner height in case it changed.
- innerHeight = select(2, inner.getSize())
- -- Check for scroll events and set direction.
- local dir
- if ev[1] == "key" and allowArrowKeys then
- if ev[2] == keys.up then dir = -1
- elseif ev[2] == keys.down then dir = 1 end
- elseif ev[1] == "mouse_scroll" and ev[3] >= x and ev[3] < x + width and ev[4] >= y and ev[4] < y + height then
- dir = ev[2]
- end
- -- If there's a scroll event, move the window vertically.
- if dir and (scrollPos + dir >= 1 and scrollPos + dir <= innerHeight - height) then
- scrollPos = scrollPos + dir
- inner.reposition(1, 2 - scrollPos)
- end
- -- Redraw scroll indicators if desired.
- if showScrollIndicators then
- outer.setBackgroundColor(bgColor)
- outer.setTextColor(fgColor)
- outer.setCursorPos(width, 1)
- outer.write(scrollPos > 1 and "\30" or " ")
- outer.setCursorPos(width, height)
- outer.write(scrollPos < innerHeight - height and "\31" or " ")
- end
- end
- end)
- return inner
- end
- --- Creates a text input box.
- ---@param win window The window to draw on
- ---@param x number The X position of the left side of the box
- ---@param y number The Y position of the box
- ---@param width number The width/length of the box
- ---@param action function|string A function or `run` event to call when the enter key is pressed
- ---@param fgColor color|nil The color of the text (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- ---@param replacement string|nil A character to replace typed characters with
- ---@param history string[]|nil A list of previous entries to provide
- ---@param completion function|nil A function to call to provide completion
- ---@param default string|nil A string to return if the box is empty
- function PrimeUI.inputBox(win, x, y, width, action, fgColor, bgColor, replacement, history, completion, default)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- expect(5, action, "function", "string")
- fgColor = expect(6, fgColor, "number", "nil") or colors.white
- bgColor = expect(7, bgColor, "number", "nil") or colors.black
- expect(8, replacement, "string", "nil")
- expect(9, history, "table", "nil")
- expect(10, completion, "function", "nil")
- expect(11, default, "string", "nil")
- -- Create a window to draw the input in.
- local box = window.create(win, x, y, width, 1)
- box.setTextColor(fgColor)
- box.setBackgroundColor(bgColor)
- box.clear()
- -- Call read() in a new coroutine.
- PrimeUI.addTask(function()
- -- We need a child coroutine to be able to redirect back to the window.
- local coro = coroutine.create(read)
- -- Run the function for the first time, redirecting to the window.
- local old = term.redirect(box)
- local ok, res = coroutine.resume(coro, replacement, history, completion, default)
- term.redirect(old)
- -- Run the coroutine until it finishes.
- while coroutine.status(coro) ~= "dead" do
- -- Get the next event.
- local ev = table.pack(os.pullEvent())
- -- Redirect and resume.
- old = term.redirect(box)
- ok, res = coroutine.resume(coro, table.unpack(ev, 1, ev.n))
- term.redirect(old)
- -- Pass any errors along.
- if not ok then error(res) end
- end
- -- Send the result to the receiver.
- if type(action) == "string" then PrimeUI.resolve("inputBox", action, res)
- else action(res) end
- -- Spin forever, because tasks cannot exit.
- while true do os.pullEvent() end
- end)
- end
- --- Creates a list of entries with toggleable check boxes.
- ---@param win window The window to draw on
- ---@param x number The X coordinate of the inside of the box
- ---@param y number The Y coordinate of the inside of the box
- ---@param width number The width of the inner box
- ---@param height number The height of the inner box
- ---@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)
- ---@param action function|string|nil A function or `run` event that's called when a selection is made
- ---@param fgColor color|nil The color of the text (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- function PrimeUI.checkSelectionBox(win, x, y, width, height, selections, action, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- expect(5, height, "number")
- expect(6, selections, "table")
- expect(7, action, "function", "string", "nil")
- fgColor = expect(8, fgColor, "number", "nil") or colors.white
- bgColor = expect(9, bgColor, "number", "nil") or colors.black
- -- Calculate how many selections there are.
- local nsel = 0
- for _ in pairs(selections) do nsel = nsel + 1 end
- -- Create the outer display box.
- local outer = window.create(win, x, y, width, height)
- outer.setBackgroundColor(bgColor)
- outer.clear()
- -- Create the inner scroll box.
- local inner = window.create(outer, 1, 1, width - 1, nsel)
- inner.setBackgroundColor(bgColor)
- inner.setTextColor(fgColor)
- inner.clear()
- -- Draw each line in the window.
- local lines = {}
- local nl, selected = 1, 1
- for k, v in pairs(selections) do
- inner.setCursorPos(1, nl)
- inner.write((v and (v == "R" and "[-] " or "[\xD7] ") or "[ ] ") .. k)
- lines[nl] = {k, not not v}
- nl = nl + 1
- end
- -- Draw a scroll arrow if there is scrolling.
- if nsel > height then
- outer.setCursorPos(width, height)
- outer.setBackgroundColor(bgColor)
- outer.setTextColor(fgColor)
- outer.write("\31")
- end
- -- Set cursor blink status.
- inner.setCursorPos(2, selected)
- inner.setCursorBlink(true)
- PrimeUI.setCursorWindow(inner)
- -- Get screen coordinates & add run task.
- local screenX, screenY = PrimeUI.getWindowPos(win, x, y)
- PrimeUI.addTask(function()
- local scrollPos = 1
- while true do
- -- Wait for an event.
- local ev = table.pack(os.pullEvent())
- -- Look for a scroll event or a selection event.
- local dir
- if ev[1] == "key" then
- if ev[2] == keys.up then dir = -1
- elseif ev[2] == keys.down then dir = 1
- elseif ev[2] == keys.space and selections[lines[selected][1]] ~= "R" then
- -- (Un)select the item.
- lines[selected][2] = not lines[selected][2]
- inner.setCursorPos(2, selected)
- inner.write(lines[selected][2] and "\xD7" or " ")
- -- Call the action if passed; otherwise, set the original table.
- if type(action) == "string" then PrimeUI.resolve("checkSelectionBox", action, lines[selected][1], lines[selected][2])
- elseif action then action(lines[selected][1], lines[selected][2])
- else selections[lines[selected][1]] = lines[selected][2] end
- -- Redraw all lines in case of changes.
- for i, v in ipairs(lines) do
- local vv = selections[v[1]] == "R" and "R" or v[2]
- inner.setCursorPos(2, i)
- inner.write((vv and (vv == "R" and "-" or "\xD7") or " "))
- end
- inner.setCursorPos(2, selected)
- end
- elseif ev[1] == "mouse_scroll" and ev[3] >= screenX and ev[3] < screenX + width and ev[4] >= screenY and ev[4] < screenY + height then
- dir = ev[2]
- end
- -- Scroll the screen if required.
- if dir and (selected + dir >= 1 and selected + dir <= nsel) then
- selected = selected + dir
- if selected - scrollPos < 0 or selected - scrollPos >= height then
- scrollPos = scrollPos + dir
- inner.reposition(1, 2 - scrollPos)
- end
- inner.setCursorPos(2, selected)
- end
- -- Redraw scroll arrows and reset cursor.
- outer.setCursorPos(width, 1)
- outer.write(scrollPos > 1 and "\30" or " ")
- outer.setCursorPos(width, height)
- outer.write(scrollPos < nsel - height + 1 and "\31" or " ")
- inner.restoreCursor()
- end
- end)
- end
- --- Creates a text box that wraps text and can have its text modified later.
- ---@param win window The parent window of the text box
- ---@param x number The X position of the box
- ---@param y number The Y position of the box
- ---@param width number The width of the box
- ---@param height number The height of the box
- ---@param text string The initial text to draw
- ---@param fgColor color|nil The color of the text (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- ---@return function redraw A function to redraw the window with new contents
- function PrimeUI.textBox(win, x, y, width, height, text, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- expect(5, height, "number")
- expect(6, text, "string")
- fgColor = expect(7, fgColor, "number", "nil") or colors.white
- bgColor = expect(8, bgColor, "number", "nil") or colors.black
- -- Create the box window.
- local box = window.create(win, x, y, width, height)
- -- Override box.getSize to make print not scroll.
- function box.getSize()
- return width, math.huge
- end
- -- Define a function to redraw with.
- local function redraw(_text)
- expect(1, _text, "string")
- -- Set window parameters.
- box.setBackgroundColor(bgColor)
- box.setTextColor(fgColor)
- box.clear()
- box.setCursorPos(1, 1)
- -- Redirect and draw with `print`.
- local old = term.redirect(box)
- print(_text)
- term.redirect(old)
- end
- redraw(text)
- return redraw
- end
- --- Draws a thin border around a screen region.
- ---@param win window The window to draw on
- ---@param x number The X coordinate of the inside of the box
- ---@param y number The Y coordinate of the inside of the box
- ---@param width number The width of the inner box
- ---@param height number The height of the inner box
- ---@param fgColor color|nil The color of the border (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- function PrimeUI.borderBox(win, x, y, width, height, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, x, "number")
- expect(3, y, "number")
- expect(4, width, "number")
- expect(5, height, "number")
- fgColor = expect(6, fgColor, "number", "nil") or colors.white
- bgColor = expect(7, bgColor, "number", "nil") or colors.black
- -- Draw the top-left corner & top border.
- win.setBackgroundColor(bgColor)
- win.setTextColor(fgColor)
- win.setCursorPos(x - 1, y - 1)
- win.write("\x9C" .. ("\x8C"):rep(width))
- -- Draw the top-right corner.
- win.setBackgroundColor(fgColor)
- win.setTextColor(bgColor)
- win.write("\x93")
- -- Draw the right border.
- for i = 1, height do
- win.setCursorPos(win.getCursorPos() - 1, y + i - 1)
- win.write("\x95")
- end
- -- Draw the left border.
- win.setBackgroundColor(bgColor)
- win.setTextColor(fgColor)
- for i = 1, height do
- win.setCursorPos(x - 1, y + i - 1)
- win.write("\x95")
- end
- -- Draw the bottom border and corners.
- win.setCursorPos(x - 1, y + height)
- win.write("\x8D" .. ("\x8C"):rep(width) .. "\x8E")
- end
- --- Draws a block of text inside a window with word wrapping, optionally resizing the window to fit.
- ---@param win window The window to draw in
- ---@param text string The text to draw
- ---@param resizeToFit boolean|nil Whether to resize the window to fit the text (defaults to false). This is useful for scroll boxes.
- ---@param fgColor color|nil The color of the text (defaults to white)
- ---@param bgColor color|nil The color of the background (defaults to black)
- ---@return number lines The total number of lines drawn
- function PrimeUI.drawText(win, text, resizeToFit, fgColor, bgColor)
- expect(1, win, "table")
- expect(2, text, "string")
- expect(3, resizeToFit, "boolean", "nil")
- fgColor = expect(4, fgColor, "number", "nil") or colors.white
- bgColor = expect(5, bgColor, "number", "nil") or colors.black
- -- Set colors.
- win.setBackgroundColor(bgColor)
- win.setTextColor(fgColor)
- -- Redirect to the window to use print on it.
- local old = term.redirect(win)
- -- Draw the text using print().
- local lines = print(text)
- -- Redirect back to the original terminal.
- term.redirect(old)
- -- Resize the window if desired.
- if resizeToFit then
- -- Get original parameters.
- local x, y = win.getPosition()
- local w = win.getSize()
- -- Resize the window.
- win.reposition(x, y, w, lines)
- end
- return lines
- end
- --- Runs a function or action after the specified time period, with optional canceling.
- ---@param time number The amount of time to wait for, in seconds
- ---@param action function|string The function to call when the timer completes, or a `run` event to send
- ---@return function cancel A function to cancel the timer
- function PrimeUI.timeout(time, action)
- expect(1, time, "number")
- expect(2, action, "function", "string")
- -- Start the timer.
- local timer = os.startTimer(time)
- -- Add a task to wait for the timer.
- PrimeUI.addTask(function()
- while true do
- -- Wait for a timer event.
- local _, tm = os.pullEvent("timer")
- if tm == timer then
- -- Fire the timer action.
- if type(action) == "string" then PrimeUI.resolve("timeout", action)
- else action() end
- end
- end
- end)
- -- Return a function to cancel the timer.
- return function() os.cancelTimer(timer) end
- end
- --PrimeUI INIT END
- ------------------------------------------------------------------------------------
- ------------------------------------------------------------------------------------
- ------------------------------------------------------------------------------------
- local comp=require"cc.shell.completion"
- local main=term.current()
- x,y=6,10
- max_x,max_y=term.getSize()
- local desc1=[[--PACKAGE DESCRIPTION--
- This package has quiet install mode.
- Use `-H` or `--help` option for more information.
- Controls:
- Enter == Continue
- Ctrl+c == Exit / Cancel
- Space == Select option
- Package version: 1.0
- Package creator: M.A.G.Gen.
- Git: https://github.com/MAGGen-hub
- LZSS.lua creator: Sebastian Steinhauer
- Git: https://github.com/kieselsteini/lzss
- PrimeUI creator: JackMacWindows
- Git: https://github.com/MCJack123/PrimeUI
- ALL LICENCES ARE PUBLIC:
- For a more detailed acquaintance visit previously mentioned links.
- What is LZSS:
- Lempel-Ziv-Storer-Szymanski (LZSS) is a lossless data compression algorithm, a derivative of LZ77, that was created in 1982 by James A. Storer and Thomas Szymanski.
- This version of LZSS is taken from Sebastian Steinhauer Git and adapted to run under Lua5.1 (Lua VM used by CraftOS).
- WARNING: Algorithm efficiency depends on count of repeating sequences of characters in input string.
- Compressed output can be bigger than input in some situations.
- --END OF PACKAGE DESCRIPTION--
- ]]
- mkgui=function(nobtn)
- local lab="LZSS Installer V1.1"
- PrimeUI.label(main,3,2,lab,colors.yellow)
- PrimeUI.horizontalLine(main,3,3,#lab + 2,colors.yellow)
- PrimeUI.borderBox(main,4,6,max_x-x,max_y-y,colors.yellow)
- PrimeUI.keyCombo(keys.c,true,false,false,"exit")
- if not nobtn then
- PrimeUI.keyAction(keys.enter,"done")
- PrimeUI.button(main,3,max_y-2,"Continue","done",colors.yellow,nil,colors.lightGray)
- PrimeUI.button(main,14,max_y-2,"Cancel","exit",colors.yellow,nil,colors.lightGray)
- else
- PrimeUI.label(main,3,max_y-2," Continue ",colors.lightGray,colors.gray)
- PrimeUI.button(main,14,max_y-2,"Cancel","exit",colors.yellow,nil,colors.lightGray)
- end
- end
- --DESCRIPTION SHOW--
- PrimeUI.clear()
- mkgui()
- local scroll_box=PrimeUI.scrollBox(main,4,6,max_x-x, max_y-y,999,true,true)
- PrimeUI.drawText(scroll_box,desc1,true)
- local _,act = PrimeUI.run()
- local ind=1
- --MODULES SELECT
- local st_name=("Startup (0.04~0.26)Kb's")
- local sh_lzss=("Shell LZSS launcher %0.2fKb's"):format(#lzss_prog_code/1024.0)
- PrimeUI.clear()
- local api_done=false
- local wnd=window.create(term.current(),4,8,max_x-x,3)--API chooser window
- local desc2={
- ["Original LZSS"]=("Original LZSS with %0.2fKb's size."):format(#lzss_api["Original LZSS"]/1024),
- ["Minified LZSS"]=("Minified API with %0.2fKb's size."):format(#lzss_api["Minified LZSS"]/1024.0),
- ["LZSS Unpack-Only"]=("LZSS Unpack function only. %0.2fKb's size. Unrecomended!"):format(#lzss_api["LZSS Unpack-Only"]/1024.0)}
- local sel_desk=desc2["Minified LZSS"]
- local api={
- ["Original LZSS"]=false,
- ["Minified LZSS"]=true,
- ["LZSS Unpack-Only"]=false}
- local mod={
- [st_name]=true,
- [sh_lzss]=true}
- if act=="done" then
- local key,value
- --API
- repeat
- PrimeUI.clear()
- mkgui()
- PrimeUI.label(main,4,6,"Select API and modules to install:",colors.yellow)
- PrimeUI.textBox(main,4,15,max_x-x,1,sel_desk,colors.yellow)
- PrimeUI.checkSelectionBox(wnd,1, 1,max_x-x,3,api,
- function(k)
- for k in pairs(api)do api[k]=false end
- api[k]=true
- sel_desk=desc2[k]
- PrimeUI.resolve(_,"api")
- end)
- PrimeUI.addTask(--task to put cursor on it's place
- function()
- for k,v in pairs(api)do
- if not v then os.queueEvent("key",keys.down,false)
- else break end
- end
- while true do coroutine.yield() end
- end)
- --wnd.redraw()PrimeUI.checkSelectionBox(main,4,12,max_x-x,2,mod,function(k,v)end)
- _,act,key,value=PrimeUI.run()
- until act~="api"
- end
- if act=="done"then
- --Modules
- PrimeUI.clear()
- mkgui()
- PrimeUI.label(main,4,6,"Select API to install:",colors.yellow)
- PrimeUI.textBox(main,4,15,max_x-x,3,"Choose additional modules",colors.yellow)
- wnd.redraw()
- PrimeUI.checkSelectionBox(main,4,12,max_x-x,2,mod,function(k,v)mod[k]=v end)
- _,act=PrimeUI.run()
- end
- local lzss_folder,prev_folder,err
- --SELECT LZSS FOLDER
- if act=="done" then
- local histor={"/","/progs/lzss","/programs/lzss","/disk/lzss","/lib/lzss","/apis/lzss","/lzss"}-- posible names for directory
- --wnd.reposition(4,9)
- --wnd.clear()
- repeat
- lzss_folder=nil
- PrimeUI.clear()
- mkgui(true)
- PrimeUI.label(main,4,6,"Choose instalation folder (use \x12):",colors.yellow)
- paintutils.drawLine(4,8,max_x-x+3,8,colors.gray)
- PrimeUI.inputBox(main,5,8,max_x-x-2,"done",colors.yellow,colors.gray,nil,histor,
- function(sLine) if #sLine>0 then return comp.dir(shell,sLine)end end,histor[#histor])
- PrimeUI.textBox(main,4,9,max_x-x,3,err or"",colors.red)
- _,act,lzss_folder=PrimeUI.run()--attempt to get the way
- _,err=pcall(function()
- if lzss_folder then --create files if posible
- if prev_folder~=lzss_folder and fs.isDir(lzss_folder) and (fs.exists(fs.combine(lzss_folder,"lzss.lua")) or fs.exists(fs.combine(lzss_folder,"lzss_api.lua")))then
- prev_folder=lzss_folder
- error("Warning! Files 'lzss.lua' and 'lzss_api.lua' will be rewriten! Are you sure? [Enter]")
- end
- local tmp1,err1
- if mod[sh_lzss] then
- tmp1,err1=fs.open(fs.combine(lzss_folder,"lzss.lua"),"w")
- err1=tmp1 or error(err1)
- end
- local tmp2,err2=fs.open(fs.combine(lzss_folder,"lzss_api.lua"),"w")
- err2=tmp2 or error(err2)
- file1=tmp1
- file2=tmp2
- end
- end)
- histor[#histor+1]=lzss_folder~=histor[#histor] and lzss_folder or nil
- until file2 or act=="exit"
- end
- err=nil
- local st_path
- --SELECT STARTUP
- if act=="done" and mod[st_name] then
- local histor={"/startup.lua","/disk/startup.lua","/disk/startup/00_lzss.lua","/startup/lzss.lua","/startup/01_lzss.lua","/startup/00_lzss.lua"}
- repeat
- PrimeUI.clear()
- mkgui(true)
- PrimeUI.label(main,4,6,"Enter startup (use \x12):",colors.yellow)
- paintutils.drawLine(4,8,max_x-x+3,8,colors.gray)
- PrimeUI.inputBox(main,5,8,max_x-x-2,"done",colors.yellow,colors.gray,nil,histor,
- function(sLine) if #sLine>0 then return comp.dirOrFile(shell,sLine)end end, histor[#histor])
- PrimeUI.textBox(main,4,9,max_x-x,3,err or"",colors.red)
- _,act,st_path=PrimeUI.run()
- _,err=pcall(function()
- if st_path then
- local tmp,err1=fs.open(st_path,"w")
- st_file=tmp or error(err1)
- end
- end)
- histor[#histor+1]=st_path~=histor[#histor] and st_path or nil
- until st_file or act=="exit"
- end
- --SIZE DEMO PART
- if act=="done" then
- local type_api="Minified LZSS"
- for k,v in pairs(api)do
- type_api=v and k or type_api
- end
- local s_api=#lzss_api[type_api]/1024
- local s_prog = mod[sh_lzss]and #lzss_prog_code/1024 or 0
- local s_stp = st_file and (((mod[sh_lzss] and 260 or 35) - 9 + #lzss_folder)/1024) or 0
- PrimeUI.clear()
- wnd.clear()
- mkgui()
- PrimeUI.label(main ,4,6,("Startup: %6.2fKb's"):format(s_stp),colors.yellow)
- PrimeUI.label(main ,4,7,(" API: %6.2fKb's"):format(s_api),colors.yellow)
- PrimeUI.label(main ,4,8,(" Prog: %6.2fKb's"):format(s_prog),colors.yellow)
- PrimeUI.label(main ,4,9,("Total Size:%6.2fKb's"):format(s_api+s_prog+s_stp),colors.yellow)
- PrimeUI.label(main ,4,10,"Continue instalation?",colors.yellow)
- _,act=PrimeUI.run()
- end
- --INSTALL PART
- if act=="done" then
- local type_api="Minified LZSS"
- for k,v in pairs(api)do
- type_api=v and k or type_api
- end
- install(lzss_folder,type_api,file1,file2,st_file)
- PrimeUI.clear()
- wnd.clear()
- mkgui()
- PrimeUI.label(main ,4,6,"Instalation completed...",colors.yellow)
- PrimeUI.label(main ,4,7,"Please reload OS...",colors.yellow)
- PrimeUI.label(main ,4,8,"Press any key to continue...",colors.yellow)
- PrimeUI.label(main ,4,9,"Program will exit automaticly after 5 seconds.",colors.yellow)
- PrimeUI.addTask(function()while true do
- local ev=os.pullEvent"key"
- ev=ev and PrimeUI.resolve()
- end
- end)
- PrimeUI.timeout(5,"done")
- PrimeUI.run()
- end
- --IF CANCELED
- if act=="exit" then
- PrimeUI.clear()
- wnd.clear()
- mkgui()
- PrimeUI.label(main ,4,6,"Instalation canceled. Press any key to exit.",colors.red)
- PrimeUI.label(main ,4,7,"Program will exit automaticly after 3 seconds.",colors.yellow)
- PrimeUI.addTask(function()while true do
- local ev=os.pullEvent"key"
- ev=ev and PrimeUI.resolve()
- end
- end)
- PrimeUI.timeout(3,"done")
- PrimeUI.run()
- end
- end
- --close all files
- _=file1 and pcall(file1.close)
- _=file2 and pcall(file2.close)
- _=st_file and pcall(st_file.close)
- if #{...}<1 then
- --restore color after UI and clear shell
- term.setTextColor(fg) term.setBackgroundColor(bg)
- shell.run"clear"
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement