Finished installer

Small bugfixes
This commit is contained in:
Robert Jelic
2025-02-23 11:11:36 +01:00
parent 8e2580c4f6
commit 96ff3ddedb
7 changed files with 402 additions and 110 deletions

View File

@@ -1,12 +1,22 @@
local basalt = require("src")
local url = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/src/"
local basalt
local releasePath = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/release/basalt.lua"
local devPath = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/src/"
local configPath = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/config.lua"
local luaLSPath = "https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/src/LuaLS.lua"
local basaltRequest = http.get(releasePath)
if not basaltRequest then
error("Failed to download Basalt")
end
basalt = load(basaltRequest.readAll(), "basalt", "bt", _ENV)()
local coloring = {foreground=colors.black, background=colors.white}
local currentScreen = 1
local screens = {}
local main = basalt.getMainFrame():setBackground(colors.black)
local config
local skipConfig = true
local function getConfig()
if not config then
@@ -25,14 +35,37 @@ end
local function getChildrenHeight(container)
local height = 0
for _, child in ipairs(container:getChildren()) do
local newHeight = child.get("y") + child.get("height")
if newHeight > height then
height = newHeight
if(child.get("visible"))then
local newHeight = child.get("y") + child.get("height")
if newHeight > height then
height = newHeight
end
end
end
return height
end
local function getScreenPosition(index)
if index <= 2 then
return (main:getWidth() * (index - 1)) + 2
end
if index == 5 then
if skipConfig then
return (main:getWidth() * 2) + 2
end
return (main:getWidth() * 4) + 2
end
if index == 3 or index == 4 then
if skipConfig then
return main:getWidth() * 10
else
return (main:getWidth() * (index - 1)) + 2
end
end
end
local function createScreen(index)
local screen = main:addFrame(coloring)
:onMouseScroll(function(self, direction)
@@ -43,25 +76,53 @@ local function createScreen(index)
self:setOffsetY(scrollOffset)
end)
:setSize("{parent.width - 2}", "{parent.height - 4}")
if(index==1)then
screen:setPosition(2, 2)
else
screen:setPosition("{parent.width * "..(index-1).." + 2}", 2)
end
screen:setPosition(function()
return getScreenPosition(index)
end, 2)
screens[index] = screen
return screen
end
local backButton
local nextButton
local function switchScreen(direction)
local newScreen = currentScreen + direction
if screens[newScreen] then
--main:setOffsetX((newScreen - 1) * main:getWidth())
if(skipConfig)then
if(newScreen==4)then
return
end
end
main:animate():moveOffset((newScreen - 1) * main:getWidth(), 0, 0.5):start()
currentScreen = newScreen
end
basalt.schedule(function()
sleep(0.1)
backButton:setVisible(true)
nextButton:setVisible(true)
if(newScreen==1)then
backButton:setVisible(false)
nextButton:setVisible(true)
end
if(newScreen==5)then
nextButton:setVisible(false)
backButton:setVisible(true)
end
if(skipConfig)then
if(newScreen==3)then
nextButton:setVisible(false)
backButton:setVisible(true)
end
end
end)
end
main:addButton()
nextButton = main:addButton()
:setBackground("{self.clicked and colors.black or colors.white}")
:setForeground("{self.clicked and colors.white or colors.black}")
:setSize(8, 1)
@@ -70,7 +131,7 @@ main:addButton()
:setIgnoreOffset(true)
:onMouseClick(function() switchScreen(1) end)
main:addButton()
backButton = main:addButton()
:setBackground("{self.clicked and colors.black or colors.white}")
:setForeground("{self.clicked and colors.white or colors.black}")
:setSize(8, 1)
@@ -78,6 +139,7 @@ main:addButton()
:setPosition(2, "{parent.height - 1}")
:setIgnoreOffset(true)
:onMouseClick(function() switchScreen(-1) end)
:setVisible(false)
-- Screen 1: Welcome
local welcomeScreen = createScreen(1)
@@ -124,45 +186,70 @@ local versionDesc = installScreen:addLabel("versionDesc")
:setSize("{parent.width - 4}", 3)
:setBackground(colors.lightGray)
versionDropdown:onSelect(function(self, index, value)
if(value == "Release") then
versionDesc:setText("The Release version is the most stable and tested version of Basalt. It is recommended for production use.")
elseif(value == "Custom") then
versionDesc:setText("The Custom version allows you to specify which elements or plugins you want to install.")
else
versionDesc:setText("The Dev version is the latest development version of Basalt. It may contain new features and improvements, but it may also have bugs and issues.")
end
end)
installScreen:addLabel(coloring)
:setText("Path:")
:setPosition(2, "{versionDesc.y + versionDesc.height + 5}")
installScreen:addLabel(coloring)
:setText("Additional Components:")
:setPosition(2, "{versionDesc.y + versionDesc.height + 1}")
local luaLSCheckbox = installScreen:addCheckbox()
local additionalComponents = installScreen:addLabel(coloring)
:setText("Additional Components:")
:setPosition(2, "{versionDesc.y + versionDesc.height + 3}")
:setVisible(false)
local luaLSCheckbox = installScreen:addCheckbox(coloring)
:setText("[ ] LLS definitions")
:setCheckedText("[x] LLS definitions")
:setPosition(2, "{versionDesc.y + versionDesc.height + 2}")
:setBackground(colors.white)
:setForeground(colors.black)
:setPosition(2, "{versionDesc.y + versionDesc.height + 4}")
:setVisible(false)
local luaMinifyCheckbox = installScreen:addCheckbox()
local luaMinifyCheckbox = installScreen:addCheckbox(coloring)
:setText("[ ] Minify Project")
:setCheckedText("[x] Minify Project")
:setPosition(2, "{versionDesc.y + versionDesc.height + 3}")
:setBackground(colors.white)
:setForeground(colors.black)
:setPosition(2, "{versionDesc.y + versionDesc.height + 5}")
:setVisible(false)
local singleFileProject = installScreen:addCheckbox(coloring)
:setText("[ ] Single File Project")
:setCheckedText("[x] Single File Project")
:setPosition(2, "{versionDesc.y + versionDesc.height + 6}")
:setVisible(false)
local installPathInput = installScreen:addInput()
:setPosition(8, "{versionDesc.y + versionDesc.height + 5}")
:setPosition(8, "{versionDesc.y + versionDesc.height + 1}")
:setPlaceholder("basalt")
:setSize(12, 1)
:setBackground(colors.black)
:setForeground(colors.white)
versionDropdown:onSelect(function(self, index, item)
if(item.text == "Release") then
versionDesc:setText("The Release version is the most stable and tested version of Basalt. It is recommended for production use.")
additionalComponents:setVisible(false)
luaLSCheckbox:setVisible(false)
luaMinifyCheckbox:setVisible(false)
singleFileProject:setVisible(false)
elseif(item.text == "Custom") then
versionDesc:setText("The Custom version allows you to specify which elements or plugins you want to install.")
additionalComponents:setVisible(true)
luaLSCheckbox:setVisible(true)
luaMinifyCheckbox:setVisible(true)
singleFileProject:setVisible(true)
else
versionDesc:setText("The Dev version is the latest development version of Basalt. It may contain new features and improvements, but it may also have bugs and issues.")
additionalComponents:setVisible(false)
luaLSCheckbox:setVisible(false)
luaMinifyCheckbox:setVisible(false)
singleFileProject:setVisible(false)
end
-- skipConfig setzen basierend auf Version
skipConfig = (item.text ~= "Custom")
-- Screens neu positionieren
for i, screen in pairs(screens) do
screen:setPosition(getScreenPosition(i), 2)
end
end)
-- Screen 3: Elements
local elementsScreen = createScreen(3)
elementsScreen:addLabel(coloring)
@@ -248,14 +335,10 @@ local function addPlugins()
end
addPlugins()
local function tableGet(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
-- Screen 5 Installation Progress
local progressScreen = createScreen(5)
local installButton
local currentlyInstalling = false
local progressBar = progressScreen:addProgressBar()
:setPosition(2, "{parent.height - 2}")
:setSize("{parent.width - 12}", 2)
@@ -265,78 +348,281 @@ local log = progressScreen:addList("log")
:setSize("{parent.width - 2}", "{parent.height - 6}")
:addItem("Starting installation...")
local function install()
local function logMessage(message)
log:addItem(message)
log:scrollToBottom()
local function logMessage(log, message)
log:addItem(message)
log:scrollToBottom()
end
local function updateProgress(progressBar, current, total)
progressBar:setProgress(math.ceil((current / total) * 100))
end
local function installRelease(installPath, log, progressBar)
logMessage(log, "Installing Release version...")
local request = http.get(releasePath)
if not request then
logMessage(log, "Failed to download release version, aborting installation.")
return
end
local fileCount = tableGet(getConfig().categories.core.files) + tableGet(getConfig().categories.libraries.files)
fileCount = fileCount + tableGet(elementsList:getSelectedItems()) + tableGet(pluginList:getSelectedItems())
progressBar:setProgress(0)
local progressStep = math.ceil(100 / fileCount)
local file = fs.open(installPath, "w")
file.write(request.readAll())
file.close()
request.close()
local function downloadFile(url, path)
logMessage("Downloading " .. url .. "...")
progressBar:setProgress(100)
logMessage(log, "Release installation complete!")
end
local function installDev(installPath, log, progressBar)
logMessage(log, "Installing Dev version...")
local config = getConfig()
if not config then
logMessage(log, "Failed to fetch config")
return
end
local function downloadFile(url, path, name, size)
logMessage(log, "Downloading " .. name..(size > 0 and " (" .. size/1000 .. " kb)" or ""))
local request = http.get(url)
if request then
local file = fs.open(path, "w")
file.write(request.readAll())
file.close()
request.close()
logMessage("Downloaded " .. url .. " to " .. path)
else
error("Failed to download " .. url)
error("Failed to download " .. name)
end
end
local path = installPathInput:getText()
if path == "" then
path = "basalt"
local totalFiles = 0
for _, category in pairs(config.categories) do
totalFiles = totalFiles + #category.files
end
local currentFile = 0
for categoryName, category in pairs(config.categories) do
for fileName, fileInfo in pairs(category.files) do
downloadFile(devPath .. fileInfo.path, fs.combine(installPath, fileInfo.path), fileName, fileInfo.size or 0)
currentFile = currentFile + 1
updateProgress(progressBar, currentFile, totalFiles)
end
end
for k, v in pairs(getConfig().categories.core.files) do
logMessage("Installing core: " .. k)
downloadFile(url..v.path, fs.combine(path, v.path))
progressBar:setProgress(progressBar:getProgress() + progressStep)
end
for k, v in pairs(getConfig().categories.libraries.files) do
logMessage("Installing library: " .. k)
downloadFile(url..v.path, fs.combine(path, v.path))
progressBar:setProgress(progressBar:getProgress() + progressStep)
end
local function installElement(name, item)
logMessage("Installing element: " .. name)
downloadFile(url..item.path, fs.combine(path, item.path))
progressBar:setProgress(progressBar:getProgress() + progressStep)
end
local function installPlugin(name, item)
logMessage("Installing plugin: " .. name)
downloadFile(url..item.path, fs.combine(path, item.path))
progressBar:setProgress(progressBar:getProgress() + progressStep)
end
for k, element in ipairs(elementsList:getSelectedItems()) do
local item = element.item
installElement(item.text, item.item)
end
for _, plugin in ipairs(pluginList:getSelectedItems()) do
local item = plugin.item
installPlugin(item.text, item.item)
end
progressBar:setProgress(100)
logMessage("Installation complete!")
logMessage(log, "Dev installation complete!")
end
local installButton = progressScreen:addButton()
local function tableGet(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
local function installCustom(installPath, log, progressBar, selectedElements, selectedPlugins, includeLuaLS, minify, singleFile)
logMessage(log, "Installing Custom version...")
local config = getConfig()
if not config then
error("Failed to fetch config")
end
local min
local project = {}
local function downloadFile(url, name, size)
logMessage(log, "Downloading " .. name..(size > 0 and " (" .. size/1000 .. " kb)" or ""))
local request = http.get(url)
if request then
local content = request.readAll()
request.close()
return content
else
error("Failed to download " .. name)
end
end
if(minify)then
local request = http.get("https://raw.githubusercontent.com/Pyroxenium/Basalt2/refs/heads/main/tools/minify.lua")
if request then
min = load(request.readAll())()
request.close()
else
logMessage(log, "Failed to download minify.lua")
return
end
end
local totalFiles = #selectedElements + #selectedPlugins
for _, category in pairs({"core", "libraries"}) do
totalFiles = totalFiles + tableGet(config.categories[category].files)
end
local currentFile = 0
for fileName, fileInfo in pairs(config.categories.core.files) do
if fileName ~= "LuaLS" or includeLuaLS then
project[fileInfo.path] = downloadFile(devPath .. fileInfo.path, fileName, fileInfo.size or 0)
currentFile = currentFile + 1
updateProgress(progressBar, currentFile, totalFiles)
end
end
for fileName, fileInfo in pairs(config.categories.libraries.files) do
project[fileInfo.path] = downloadFile(devPath .. fileInfo.path, fileName, fileInfo.size or 0)
currentFile = currentFile + 1
updateProgress(progressBar, currentFile, totalFiles)
end
for _, element in ipairs(selectedElements) do
local fileInfo = config.categories.elements.files[element.text]
basalt.LOGGER.debug(element.text)
project[fileInfo.path] = downloadFile(devPath .. fileInfo.path, element.text, fileInfo.size or 0)
currentFile = currentFile + 1
updateProgress(progressBar, currentFile, totalFiles)
end
for _, plugin in ipairs(selectedPlugins) do
local fileInfo = config.categories.plugins.files[plugin.text]
project[fileInfo.path] = downloadFile(devPath .. fileInfo.path, plugin.text, fileInfo.size or 0)
currentFile = currentFile + 1
updateProgress(progressBar, currentFile, totalFiles)
end
if minify then
logMessage(log, "Minifying project...")
for path, content in pairs(project) do
local success, minifiedContent = min(content)
if(success)then
project[path] = minifiedContent
else
logMessage(log, "Failed to minify " .. path)
return
end
end
end
if(singleFile)then
installPath = installPath:gsub(".lua", "")..".lua"
local output = {
'local minified = true\n',
'local minified_elementDirectory = {}\n',
'local minified_pluginDirectory = {}\n',
'local project = {}\n',
'local loadedProject = {}\n',
'local baseRequire = require\n',
'require = function(path) if(project[path..".lua"])then if(loadedProject[path]==nil)then loadedProject[path] = project[path..".lua"]() end return loadedProject[path] end baseRequire(path) end\n'
}
for filePath, content in pairs(project) do
local elementName = filePath:match("^elements/(.+)%.lua$")
if elementName then
table.insert(output, string.format(
'minified_elementDirectory["%s"] = {}\n',
elementName
))
end
local pluginName = filePath:match("^plugins/(.+)%.lua$")
if pluginName then
table.insert(output, string.format(
'minified_pluginDirectory["%s"] = {}\n',
pluginName
))
end
end
for filePath, content in pairs(project) do
table.insert(output, string.format(
'project["%s"] = function(...) %s end\n',
filePath, content
))
end
table.insert(output, 'return project["main.lua"]()')
local out = fs.open(installPath, "w")
if(out)then
out.write(table.concat(output))
out.close()
if(includeLuaLS)then
local luaLS = downloadFile(luaLSPath, "LuaLS", 0)
local luaLSDir = fs.getDir(installPath)
local file = fs.open(fs.combine(luaLSDir, "LuaLS.lua"), "w")
file.write(luaLS)
file.close()
end
else
logMessage(log, "Failed to write to " .. installPath)
return
end
else
for filePath, content in pairs(project) do
local out = fs.open(fs.combine(installPath, filePath), "w")
if(out)then
out.write(content)
out.close()
else
logMessage(log, "Failed to write to " .. fs.combine(installPath, filePath))
return
end
end
if(includeLuaLS)then
local luaLS = downloadFile(luaLSPath, "LuaLS", 0)
local luaLSDir = fs.combine(installPath, "LuaLS.lua")
local file = fs.open(luaLSDir, "w")
file.write(luaLS)
file.close()
end
end
logMessage(log, "Custom installation complete!")
end
local function installBasalt()
currentlyInstalling = true
installButton:setVisible(false)
local selection = versionDropdown:getSelectedItems()[1]
if(selection==nil)then
selection = "Release"
else
selection = selection.text
end
local path = installPathInput:getText()
if(path=="")then
path = "basalt"
else
path = path:gsub(".lua", "")
end
if(selection == "Release")then
installRelease(path..".lua", log, progressBar)
elseif(selection == "Dev")then
installDev(path, log, progressBar)
else
installCustom(path, log, progressBar, elementsList:getSelectedItems(), pluginList:getSelectedItems(), luaLSCheckbox:getChecked(), luaMinifyCheckbox:getChecked(), singleFileProject:getChecked())
end
currentlyInstalling = false
installButton:setVisible(true)
end
installButton = progressScreen:addButton()
:setBackground("{self.clicked and colors.lightGray or colors.black}")
:setForeground("{self.clicked and colors.black or colors.lightGray}")
:setText("Install")
:setPosition("{parent.width - 9}", "{parent.height - 3}")
:setSize(9, 1)
:onMouseClick(function(self)
if(currentlyInstalling)then
return
end
basalt.schedule(installBasalt)
end)
local closeButton = progressScreen:addButton()
:setBackground("{self.clicked and colors.lightGray or colors.black}")
:setForeground("{self.clicked and colors.black or colors.lightGray}")
:setText("Close")
:setPosition("{parent.width - 9}", "{parent.height - 1}")
:setSize(9, 1)
:onMouseClick(install)
:onMouseClick(function(self)
basalt.stop()
end)
basalt.run()

View File

@@ -102,6 +102,7 @@ end
--- @param child table The child to check
--- @return boolean boolean the child is visible
function Container:isChildVisible(child)
if(child.get("visible") == false)then return false end
local containerW, containerH = self.get("width"), self.get("height")
local offsetX, offsetY = self.get("offsetX"), self.get("offsetY")
@@ -585,6 +586,7 @@ function Container:destroy()
child:destroy()
end
VisualElement.destroy(self)
return self
end
return Container

View File

@@ -106,7 +106,7 @@ function Dropdown:render()
if #text == 0 then
local selectedItems = self:getSelectedItems()
if #selectedItems > 0 then
local selectedItem = selectedItems[1].item
local selectedItem = selectedItems[1]
text = selectedItem.text or ""
end
end

View File

@@ -92,7 +92,9 @@ function List:getSelectedItems()
local selected = {}
for i, item in ipairs(self.get("items")) do
if type(item) == "table" and item.selected then
table.insert(selected, {index = i, item = item})
local selectedItem = item
selectedItem.index = i
table.insert(selected, selectedItem)
end
end
return selected
@@ -211,21 +213,21 @@ function List:render()
local bg = item.background or self.get("background")
self:textBg(1, i, string.rep(" ", width), bg)
self:textFg(1, i, separatorText, fg)
self:textFg(1, i, separatorText:sub(1, width), fg)
else
local text = item.text
local isSelected = item.selected
local bg = isSelected and
local bg = isSelected and
(item.selectedBackground or self.get("selectedBackground")) or
(item.background or self.get("background"))
local fg = isSelected and
local fg = isSelected and
(item.selectedForeground or self.get("selectedForeground")) or
(item.foreground or self.get("foreground"))
self:textBg(1, i, string.rep(" ", width), bg)
self:textFg(1, i, text, fg)
self:textFg(1, i, text:sub(1, width), fg)
end
end
end

View File

@@ -107,7 +107,6 @@ function Menu:mouse_click(button, x, y)
self.get("items")[i] = item
end
-- Wenn kein Multi-Selection, alle anderen deselektieren
if not self.get("multiSelection") then
for _, otherItem in ipairs(self.get("items")) do
if type(otherItem) == "table" then
@@ -116,7 +115,6 @@ function Menu:mouse_click(button, x, y)
end
end
-- Toggle Selection
item.selected = not item.selected
if item.callback then

View File

@@ -63,6 +63,9 @@ VisualElement.defineProperty(VisualElement, "visible", {default = true, type = "
self.parent.set("childrenSorted", false)
self.parent.set("childrenEventsSorted", false)
end
if(value==false)then
self.set("clicked", false)
end
return value
end})

View File

@@ -169,18 +169,17 @@ local function updateEvent(event, ...)
if lazyElementsEventHandler(event, ...) then return end
if(mainFrame)then
if(mainFrame:dispatchEvent(event, ...))then
return
end
mainFrame:dispatchEvent(event, ...)
end
for _, func in ipairs(basalt._schedule) do
if(event==func.filter)then
for k, func in ipairs(basalt._schedule) do
if(event==func.filter)or(func.filter==nil)then
local ok, result = coroutine.resume(func.coroutine, event, ...)
if(not ok)then
errorManager.header = "Basalt Schedule Error"
errorManager.error(result)
end
func.filter = result
end
if(coroutine.status(func.coroutine)=="dead")then
basalt.removeSchedule(func.coroutine)
@@ -213,9 +212,9 @@ end
--- @shortDescription Stops the Basalt runtime
--- @usage basalt.stop()
function basalt.stop()
updaterActive = false
term.clear()
term.setCursorPos(1,1)
updaterActive = false
end
--- Starts the Basalt runtime
@@ -230,7 +229,9 @@ function basalt.run(isActive)
renderFrames()
while updaterActive do
updateEvent(os.pullEventRaw())
renderFrames()
if(updaterActive)then
renderFrames()
end
end
end
while updaterActive do