Updated markdown parser, testing it

This commit is contained in:
Robert Jelic
2025-02-17 09:36:51 +01:00
parent daae1ddb3d
commit cf49f69612
7 changed files with 167 additions and 55 deletions

View File

@@ -75,7 +75,7 @@ function BaseElement:init(props, basalt)
return self
end
--- Post initialization hook
--- Post initialization
--- @return table self The BaseElement instance
function BaseElement:postInit()
if(self._props)then
@@ -174,6 +174,8 @@ function BaseElement:handleEvent(event, ...)
return false
end
--- Returns the base frame of the element
--- @return table BaseFrame The base frame of the element
function BaseElement:getBaseFrame()
if self.parent then
return self.parent:getBaseFrame()
@@ -181,8 +183,26 @@ function BaseElement:getBaseFrame()
return self
end
--- Destroys the element and cleans up all references
--- @usage element:destroy()
function BaseElement:destroy()
-- Remove from parent if exists
if self.parent then
self.parent:removeChild(self)
end
for event in pairs(self._registeredEvents) do
self:listenEvent(event, false)
end
self._values.eventCallbacks = {}
self._props = nil
self._values = nil
self.basalt = nil
self.parent = nil
self.__index = nil
setmetatable(self, nil)
end
--- Requests a render update for this element

View File

@@ -464,4 +464,11 @@ function Container:render()
end
end
function Container:destroy()
for _, child in ipairs(self._values.children) do
child:destroy()
end
VisualElement.destroy(self)
end
return Container

View File

@@ -47,7 +47,7 @@ end
function Table:sortData(columnIndex)
local data = self.get("data")
local direction = self.get("sortDirection")
table.sort(data, function(a, b)
if direction == "asc" then
return a[columnIndex] < b[columnIndex]
@@ -55,7 +55,7 @@ function Table:sortData(columnIndex)
return a[columnIndex] > b[columnIndex]
end
end)
self.set("data", data)
return self
end
@@ -65,7 +65,6 @@ function Table:mouse_click(button, x, y)
local relX, relY = self:getRelativePosition(x, y)
-- Header-Click für Sorting
if relY == 1 then
local currentX = 1
for i, col in ipairs(self.get("columns")) do
@@ -83,7 +82,6 @@ function Table:mouse_click(button, x, y)
end
end
-- Row-Selection (berücksichtigt Scroll-Offset)
if relY > 1 then
local rowIndex = relY - 2 + self.get("scrollOffset")
if rowIndex >= 0 and rowIndex < #self.get("data") then
@@ -98,7 +96,7 @@ function Table:mouse_scroll(direction, x, y)
local data = self.get("data")
local height = self.get("height")
local visibleRows = height - 2
local maxScroll = math.max(0, #data - visibleRows + 1) -- +1 korrigiert den Scroll-Bereich
local maxScroll = math.max(0, #data - visibleRows + 1)
local newOffset = math.min(maxScroll, math.max(0, self.get("scrollOffset") + direction))
self.set("scrollOffset", newOffset)
@@ -125,14 +123,12 @@ function Table:render()
currentX = currentX + col.width
end
-- Angepasste Berechnung der sichtbaren Zeilen
local visibleRows = height - 2 -- Verfügbare Zeilen (minus Header)
local visibleRows = height - 2
for y = 2, height do
local rowIndex = y - 2 + scrollOffset
local rowData = data[rowIndex + 1]
-- Zeile nur rendern wenn es auch Daten dafür gibt
if rowData and (rowIndex + 1) <= #data then -- Korrigierte Bedingung
if rowData and (rowIndex + 1) <= #data then
currentX = 1
local bg = (rowIndex + 1) == selected and self.get("selectedColor") or self.get("background")
@@ -145,33 +141,28 @@ function Table:render()
currentX = currentX + col.width
end
else
-- Leere Zeile füllen
self:blit(1, y, string.rep(" ", self.get("width")),
string.rep(tHex[self.get("foreground")], self.get("width")),
string.rep(tHex[self.get("background")], self.get("width")))
end
end
-- Scrollbar Berechnung überarbeitet
if #data > height - 2 then
local scrollbarHeight = height - 2
local thumbSize = math.max(1, math.floor(scrollbarHeight * (height - 2) / #data))
-- Thumb Position korrigiert
local maxScroll = #data - (height - 2) + 1 -- +1 für korrekte End-Position
local maxScroll = #data - (height - 2) + 1
local scrollPercent = scrollOffset / maxScroll
local thumbPos = 2 + math.floor(scrollPercent * (scrollbarHeight - thumbSize))
if scrollOffset >= maxScroll then
thumbPos = height - thumbSize -- Exakt am Ende
thumbPos = height - thumbSize
end
-- Scrollbar Background
for y = 2, height do
self:blit(self.get("width"), y, "\127", tHex[colors.gray], tHex[colors.gray])
end
-- Thumb zeichnen
for y = thumbPos, math.min(height, thumbPos + thumbSize - 1) do
self:blit(self.get("width"), y, "\127", tHex[colors.white], tHex[colors.white])
end

View File

@@ -2,8 +2,6 @@ local elementManager = require("elementManager")
local BaseElement = elementManager.getElement("BaseElement")
local tHex = require("libraries/colorHex")
---@alias color number
---@class VisualElement : BaseElement
local VisualElement = setmetatable({}, BaseElement)
VisualElement.__index = VisualElement
@@ -62,13 +60,24 @@ VisualElement.defineProperty(VisualElement, "visible", {default = true, type = "
return value
end})
---@combinedProperty position x y
---@combinedProperty position {x y} Position of the element
VisualElement.combineProperties(VisualElement, "position", "x", "y")
---@combinedProperty size width height
---@combinedProperty size {width height} Size of the element
VisualElement.combineProperties(VisualElement, "size", "width", "height")
---@combinedProperty color foreground background
---@combinedProperty color {foreground background} Color of the element
VisualElement.combineProperties(VisualElement, "color", "foreground", "background")
---@event onMouseClick {button number, x number, y number} Fired when the element is clicked
---@event onMouseUp {button number, x number, y number} Fired when the mouse is released
---@event onMouseRelease {button number, x number, y number} Fired when the mouse is released
---@event onMouseDrag {button number, x number, y number} Fired when the mouse is dragged
---@event onFocus {-} Fired when the element is focused
---@event onBlur {-} Fired when the element is blurred
---@event onKey {key number, code number, isRepeat boolean} Fired when a key is pressed
---@event onKeyUp {key number, code number} Fired when a key is released
---@event onChar {char string} Fired when a key is pressed
VisualElement.listenTo(VisualElement, "focus")
VisualElement.listenTo(VisualElement, "blur")
@@ -90,14 +99,7 @@ function VisualElement:init(props, basalt)
self.set("type", "VisualElement")
end
--- Draws a text character/fg/bg at the specified position with a certain size, used in the rendering system
--- @param x number The x position to draw
--- @param y number The y position to draw
--- @param width number The width of the element
--- @param height number The height of the element
--- @param text string The text char to draw
--- @param fg color The foreground color
--- @param bg color The background color
---@protected
function VisualElement:multiBlit(x, y, width, height, text, fg, bg)
x = x + self.get("x") - 1
y = y + self.get("y") - 1
@@ -260,7 +262,6 @@ function VisualElement:setCursor(x, y, blink)
end
--- Renders the element
--- @usage element:render()
function VisualElement:render()
if(not self.get("backgroundEnabled"))then
return

View File

@@ -1,3 +1,8 @@
---@class Log
---@field _logs table
---@field _enabled boolean
---@field _logToFile boolean
---@field _logFile string
local Log = {}
Log._logs = {}
Log._enabled = true
@@ -6,7 +11,6 @@ Log._logFile = "basalt.log"
fs.delete(Log._logFile)
-- Log levels
Log.LEVEL = {
DEBUG = 1,
INFO = 2,
@@ -28,10 +32,12 @@ local levelColors = {
[Log.LEVEL.ERROR] = colors.red
}
--- Sets if the logger should log to a file.
function Log.setLogToFile(enable)
Log._logToFile = enable
end
--- sets if the logger should log
function Log.setEnabled(enable)
Log._enabled = enable
end
@@ -51,7 +57,6 @@ local function log(level, ...)
local timeStr = os.date("%H:%M:%S")
-- Get caller info (skip log function and Log.debug/info/etc functions)
local info = debug.getinfo(3, "Sl")
local source = info.source:match("@?(.*)")
local line = info.currentline
@@ -69,9 +74,7 @@ local function log(level, ...)
local fullMessage = string.format("%s %s%s %s", timeStr, levelStr, levelMsg, message)
-- File output
writeToFile(fullMessage)
-- Store in memory
table.insert(Log._logs, {
time = timeStr,
level = level,
@@ -79,9 +82,17 @@ local function log(level, ...)
})
end
--- Sends a debug message to the logger.
--- @vararg string The message to log
function Log.debug(...) log(Log.LEVEL.DEBUG, ...) end
--- Sends an info message to the logger.
--- @vararg string The message to log
function Log.info(...) log(Log.LEVEL.INFO, ...) end
--- Sends a warning message to the logger.
--- @vararg string The message to log
function Log.warn(...) log(Log.LEVEL.WARN, ...) end
--- Sends an error message to the logger.
--- @vararg string The message to log
function Log.error(...) log(Log.LEVEL.ERROR, ...) end
Log.info("Logger initialized")

View File

@@ -8,7 +8,14 @@ local propertySystem = require("propertySystem")
--- Before you can access Basalt, you need to add the following code on top of your file:
--- @usage local basalt = require("basalt")
--- What this code does is it loads basalt into the project, and you can access it by using the variable defined as "basalt".
-- @module Basalt
--- @class Basalt
--- @field traceback boolean Whether to show a traceback on errors
--- @field _events table A table of events and their callbacks
--- @field _schedule function[] A table of scheduled functions
--- @field _plugins table A table of plugins
--- @field LOGGER Log The logger instance
--- @field path string The path to the Basalt library
local basalt = {}
basalt.traceback = true
basalt._events = {}
@@ -79,7 +86,8 @@ function basalt.create(type, properties, lazyLoading, parent)
end
end
--- Creates and returns a new frame
--- Creates and returns a new BaseFrame
--- @shortDescription Creates a new BaseFrame
--- @return table BaseFrame The created frame instance
--- @usage local mainFrame = basalt.createFrame()
function basalt.createFrame()
@@ -90,6 +98,7 @@ function basalt.createFrame()
end
--- Returns the element manager instance
--- @shortDescription Returns the element manager
--- @return table ElementManager The element manager
--- @usage local manager = basalt.getElementManager()
function basalt.getElementManager()
@@ -97,6 +106,7 @@ function basalt.getElementManager()
end
--- Gets or creates the main frame
--- @shortDescription Gets or creates the main frame
--- @return BaseFrame table The main frame instance
--- @usage local frame = basalt.getMainFrame()
function basalt.getMainFrame()
@@ -107,6 +117,7 @@ function basalt.getMainFrame()
end
--- Sets the active frame
--- @shortDescription Sets the active frame
--- @param frame table The frame to set as active
--- @usage basalt.setActiveFrame(myFrame)
function basalt.setActiveFrame(frame)
@@ -114,6 +125,7 @@ function basalt.setActiveFrame(frame)
end
--- Schedules a function to be updated
--- @shortDescription Schedules a function to be updated
--- @function scheduleUpdate
--- @param func function The function to schedule
--- @return number Id The schedule ID
@@ -124,6 +136,7 @@ function basalt.scheduleUpdate(func)
end
--- Removes a scheduled update
--- @shortDescription Removes a scheduled update
--- @function removeSchedule
--- @param id number The schedule ID to remove
--- @usage basalt.removeSchedule(scheduleId)
@@ -131,7 +144,7 @@ function basalt.removeSchedule(id)
basalt._schedule[id] = nil
end
--- @local Internal event handler
---@private
local function updateEvent(event, ...)
if(event=="terminate")then basalt.stop() end
if lazyElementsEventHandler(event, ...) then return end
@@ -149,7 +162,7 @@ local function updateEvent(event, ...)
end
end
--- @local Internal render function
---@private
local function renderFrames()
if(mainFrame)then
mainFrame:render()
@@ -157,6 +170,7 @@ local function renderFrames()
end
--- Updates all scheduled functions
--- @shortDescription Updates all scheduled functions
--- @usage basalt.update()
function basalt.update()
for k,v in pairs(basalt._schedule) do
@@ -167,6 +181,7 @@ function basalt.update()
end
--- Stops the Basalt runtime
--- @shortDescription Stops the Basalt runtime
--- @usage basalt.stop()
function basalt.stop()
term.clear()
@@ -175,6 +190,7 @@ function basalt.stop()
end
--- Starts the Basalt runtime
--- @shortDescription Starts the Basalt runtime
--- @param isActive? boolean Whether to start active (default: true)
--- @usage basalt.run()
--- @usage basalt.run(false)
@@ -197,6 +213,10 @@ function basalt.run(isActive)
end
end
--- Returns a Plugin API
--- @shortDescription Returns a Plugin API
--- @param name string The name of the plugin
--- @return table Plugin The plugin API
function basalt.getAPI(name)
return elementManager.getAPI(name)
end

View File

@@ -11,7 +11,12 @@ local commentTypes = {
"function",
"local",
"shortDescription",
"property"
"property",
"combinedProperty",
"event",
"private",
"protected",
"field"
}
local function extractComment(line)
@@ -60,8 +65,11 @@ end
function markdown.parse(content)
local blocks = {}
local properties = {}
local combinedProperties = {}
local events = {}
local fields = {}
local currentBlock = {type = "comment", desc = {}}
local skipNextFunction = false
for line in content:gsub("\r\n", "\n"):gmatch("([^\n]*)\n?") do
if line:match("^%s*$") or line == "" then
@@ -76,6 +84,8 @@ function markdown.parse(content)
if(commentType == "desc") then
currentBlock.usageIsActive = false
table.insert(currentBlock.desc, value)
elseif(commentType == "private")or(commentType == "protected")then
skipNextFunction = true
else
if(commentType == "module")then
currentBlock.usageIsActive = false
@@ -100,6 +110,11 @@ function markdown.parse(content)
elseif(commentType == "property")then
currentBlock = {type = "comment", desc = {}}
table.insert(properties, value)
elseif(commentType == "combinedProperty")then
currentBlock = {type = "comment", desc = {}}
table.insert(combinedProperties, value)
elseif(commentType == "field")then
table.insert(fields, value)
elseif(commentType == "event")then
currentBlock = {type = "comment", desc = {}}
table.insert(events, value)
@@ -113,10 +128,14 @@ function markdown.parse(content)
end
else
local funcName = getFunctionName(line)
if funcName then
currentBlock.func = funcName
currentBlock.type = "function"
if(skipNextFunction)then
skipNextFunction = false
else
local funcName = getFunctionName(line)
if funcName then
currentBlock.func = funcName
currentBlock.type = "function"
end
end
end
end
@@ -141,7 +160,7 @@ function markdown.parse(content)
return a.func < b.func
end)
markdown.blocks = {properties = properties, events = events}
markdown.blocks = {combinedProperties = combinedProperties, properties = properties, events = events, fields = fields}
for _, block in ipairs(otherBlocks) do
table.insert(markdown.blocks, block)
end
@@ -192,6 +211,27 @@ local function markdownFunction(block)
return output
end
local function markdownFields()
if(#markdown.blocks.fields<=0)then
return ""
end
local output = "\n## Fields\n\n|Field|Type|Description|\n|---|---|---|\n"
for _, block in pairs(markdown.blocks.fields) do
local name, rest = block:match("([%w_]+)%s+(.+)")
if name and rest then
local fieldType, desc = rest:match("([^%s].-)%s+([^%s].*)")
if fieldType and desc then
output = output .. string.format("|%s|`%s`|%s|\n",
name,
fieldType,
desc or ""
)
end
end
end
return output
end
local function markdownProperties()
if(#markdown.blocks.properties<=0)then
return ""
@@ -204,18 +244,36 @@ local function markdownProperties()
return output
end
local function markdownCombinedProperties()
if(markdown.blocks.combinedProperties==nil)then
return ""
end
if(#markdown.blocks.combinedProperties<=0)then
return ""
end
local output = "\n## Combined Properties\n\n|Name|Properties|Description|\n|---|---|---|\n"
for _, block in pairs(markdown.blocks.combinedProperties) do
local name, paramType, defaultValue, desc = block:match("([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+(.*)")
output = output .. string.format("|%s|%s|%s|%s\n", name, paramType, defaultValue, desc)
end
return output
end
local function markdownEvents()
if(#markdown.blocks.events<=0)then
return ""
end
local output = "\n## Events\n\n"
for _, block in pairs(markdown.blocks) do
if block.type == "module" or block.type == "class" then
if(block.event~=nil)then
for _, line in pairs(block.event) do
output = output .. "* " .. line .. "\n"
end
end
local output = "\n## Events\n\n|Event|Parameters|Description|\n|---|---|---|\n"
for _, event in pairs(markdown.blocks.events) do
local name, params, desc = event:match("([%w_]+)%s+{([^}]+)}%s*(.*)")
if name and params then
local formattedParams = params:gsub("%s*,%s*", ", ")
output = output .. string.format("|%s|`%s`|%s|\n",
name,
formattedParams,
desc or ""
)
end
end
return output
@@ -263,7 +321,9 @@ local function markdownModule(block)
output = output .. line .. "\n"
end
output = output .. markdownFields()
output = output .. markdownProperties()
output = output .. markdownCombinedProperties()
output = output .. markdownEvents()
output = output .. markdownModuleOrClassFunctions(block)
output = output .. "\n"
@@ -288,7 +348,9 @@ local function markdownClass(block)
output = output .. line .. "\n"
end
output = output .. markdownFields()
output = output .. markdownProperties()
output = output .. markdownCombinedProperties()
output = output .. markdownEvents()
output = output .. markdownModuleOrClassFunctions(block)
output = output .. "\n"