From cf49f69612b88cc049edc4b8b3552dc889aeaefe Mon Sep 17 00:00:00 2001 From: Robert Jelic <36573031+NoryiE@users.noreply.github.com> Date: Mon, 17 Feb 2025 09:36:51 +0100 Subject: [PATCH] Updated markdown parser, testing it --- src/elements/BaseElement.lua | 22 ++++++++- src/elements/Container.lua | 7 +++ src/elements/Table.lua | 27 ++++------ src/elements/VisualElement.lua | 29 +++++------ src/log.lua | 19 +++++-- src/main.lua | 28 +++++++++-- tools/markdown.lua | 90 ++++++++++++++++++++++++++++------ 7 files changed, 167 insertions(+), 55 deletions(-) diff --git a/src/elements/BaseElement.lua b/src/elements/BaseElement.lua index a101c44..9749abe 100644 --- a/src/elements/BaseElement.lua +++ b/src/elements/BaseElement.lua @@ -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 diff --git a/src/elements/Container.lua b/src/elements/Container.lua index 62f9c49..a7df34d 100644 --- a/src/elements/Container.lua +++ b/src/elements/Container.lua @@ -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 \ No newline at end of file diff --git a/src/elements/Table.lua b/src/elements/Table.lua index e3b364d..7c8c44b 100644 --- a/src/elements/Table.lua +++ b/src/elements/Table.lua @@ -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 diff --git a/src/elements/VisualElement.lua b/src/elements/VisualElement.lua index 601c861..36c5d1d 100644 --- a/src/elements/VisualElement.lua +++ b/src/elements/VisualElement.lua @@ -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 diff --git a/src/log.lua b/src/log.lua index 235c506..6535349 100644 --- a/src/log.lua +++ b/src/log.lua @@ -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") diff --git a/src/main.lua b/src/main.lua index 0a28916..8f78ef6 100644 --- a/src/main.lua +++ b/src/main.lua @@ -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 diff --git a/tools/markdown.lua b/tools/markdown.lua index 88f6ef0..d172f6d 100644 --- a/tools/markdown.lua +++ b/tools/markdown.lua @@ -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"