From c2e8d09f10309940887a73b053a8e419d103c1ea Mon Sep 17 00:00:00 2001 From: Robert Jelic Date: Mon, 10 Feb 2025 06:23:21 +0100 Subject: [PATCH] Test --- .github/workflows/docs.yml | 17 +- Makefile | 58 ------- config.ld | 8 - ldoc.css | 305 --------------------------------- manual.md | 1 - markdown.lua | 316 +++++++++++++++++++++++++++++++++++ src/elements/BaseElement.lua | 37 +++- src/main.lua | 32 +--- 8 files changed, 370 insertions(+), 404 deletions(-) delete mode 100644 Makefile delete mode 100644 config.ld delete mode 100644 ldoc.css delete mode 100644 manual.md create mode 100644 markdown.lua diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 852aa9c..b701456 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,4 +1,3 @@ -# Based on https://gist.github.com/domenic/ec8b0fc8ab45f39403dd name: Build Docs on: pull_request: @@ -18,15 +17,17 @@ jobs: uses: leafo/gh-actions-lua@v8 with: luaVersion: 5.4 - - name: Setup Lua Rocks - uses: leafo/gh-actions-luarocks@v4 - - name: Setup dependencies - run: luarocks install ldoc - - name: Build docs - run: make doc-site + - name: Create docs directory + run: mkdir -p docs/references + - name: Process markdown files + run: | + find src -type f -name "*.lua" | while read file; do + filename=$(basename "$file") + lua markdown.lua "$file" "docs/references/${filename%.lua}.md" + done - name: Deploy if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./out \ No newline at end of file + publish_dir: ./docs/references \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index 8feb238..0000000 --- a/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -LUA= $(shell echo `which lua`) -LUA_BINDIR= $(shell echo `dirname $(LUA)`) -LUA_PREFIX= $(shell echo `dirname $(LUA_BINDIR)`) -LUA_SHAREDIR=$(LUA_PREFIX)/share/lua/5.1 - -_REPODIR != cd "$(shell dirname $(firstword $(MAKEFILE_LIST)))/" && pwd - -ldoc: - -install: install_parts - @echo "lua $(LUA_SHAREDIR)/ldoc.lua \$$*" > "$(DESTDIR)$(LUA_BINDIR)/ldoc" - @chmod -v +x "$(DESTDIR)$(LUA_BINDIR)/ldoc" - -install_luajit: install_parts - @echo "luajit $(LUA_SHAREDIR)/ldoc.lua \$$*" > "$(DESTDIR)$(LUA_BINDIR)/ldoc" - @chmod -v +x "$(DESTDIR)$(LUA_BINDIR)/ldoc" - -install_parts: - @if [ ! -d "$(DESTDIR)$(LUA_BINDIR)" ]; then \ - mkdir -vp "$(DESTDIR)$(LUA_BINDIR)"; \ - fi - @mkdir -vp "$(DESTDIR)$(LUA_SHAREDIR)" - @cp -v ldoc.lua "$(DESTDIR)$(LUA_SHAREDIR)" - @cp -vr ldoc "$(DESTDIR)$(LUA_SHAREDIR)" - -uninstall: - @-rm -v "$(DESTDIR)$(LUA_SHAREDIR)/ldoc.lua" - @-rm -vr "$(DESTDIR)$(LUA_SHAREDIR)/ldoc" - @-rm -v "$(DESTDIR)$(LUA_BINDIR)/ldoc" - -test: test-basic test-example test-md test-tables - -RUN=&& lua $(_REPODIR)/ldoc.lua . && diff -r doc cdocs && echo ok - -test-prep: - find -type d -name doc -execdir rsync -av --del {}/ cdocs/ \; - -test-basic: - cd tests $(RUN) - -test-example: - cd tests/example $(RUN) - -test-md: - cd tests/md-test $(RUN) - -test-tables: - cd tests/simple $(RUN) - -test-clean: clean-basic clean-example clean-md clean-tables - -.PHONY: doc-site clean - -doc-site: - ldoc . - -clean: - rm -rf out diff --git a/config.ld b/config.ld deleted file mode 100644 index ec31169..0000000 --- a/config.ld +++ /dev/null @@ -1,8 +0,0 @@ -project = 'Basalt 2' -title = 'Basalt Documentation' -description = 'A UI Framework for ComputerCraft' -file = 'src' -dir = 'out' -format = 'markdown' -all = true -style = true \ No newline at end of file diff --git a/ldoc.css b/ldoc.css deleted file mode 100644 index 3fc7a39..0000000 --- a/ldoc.css +++ /dev/null @@ -1,305 +0,0 @@ -/* BEGIN RESET - -Copyright (c) 2010, Yahoo! Inc. All rights reserved. -Code licensed under the BSD License: -http://developer.yahoo.com/yui/license.html -version: 2.8.2r1 -*/ -html { - color: #dfdfdf; - background: #1b1b1b; -} -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { - margin: 0; - padding: 0; -} -table { - border-collapse: collapse; - border-spacing: 0; -} -fieldset,img { - border: 0; -} -address,caption,cite,code,dfn,em,strong,th,var,optgroup { - font-style: inherit; - font-weight: inherit; -} -del,ins { - text-decoration: none; -} -li { - list-style: bullet; - margin-left: 20px; -} -caption,th { - text-align: left; -} -h1,h2,h3,h4,h5,h6 { - font-size: 100%; - font-weight: bold; -} -q:before,q:after { - content: ''; -} -abbr,acronym { - border: 0; - font-variant: normal; -} -sup { - vertical-align: baseline; -} -sub { - vertical-align: baseline; -} -legend { - color: #000; -} -input,button,textarea,select,optgroup,option { - font-family: inherit; - font-size: inherit; - font-style: inherit; - font-weight: inherit; -} -input,button,textarea,select {*font-size:100%;} -/* END RESET */ - -body { - margin-left: 1em; - margin-right: 1em; - font-family: arial, helvetica, geneva, sans-serif; - background-color: #1a1a1a; - color: #e0e0e0; -} - -code, tt { - font-family: monospace; - color: #88ccff; -} - -body, p, td, th { font-size: .95em; line-height: 1.2em;} - -p, ul { margin: 10px 0 0 10px;} - -strong { font-weight: bold;} - -em { font-style: italic;} - -h1 { - font-size: 1.5em; - margin: 0 0 20px 0; - color: #ffffff; -} -h2, h3, h4 { margin: 15px 0 10px 0; color: #ffffff; } -h2 { font-size: 1.25em; } -h3 { font-size: 1.15em; } -h4 { font-size: 1.06em; } - -a:link { font-weight: bold; color: #66b3ff; text-decoration: none; } -a:visited { font-weight: bold; color: #b366ff; text-decoration: none; } -a:link:hover { text-decoration: underline; } - -hr { - color: #c9c9c9; - background: #444444; - height: 1px; -} - -blockquote { margin-left: 3em; } - -ul { list-style-type: disc; } - -p.name { - font-family: "Andale Mono", monospace; - padding-top: 1em; -} - -pre.example { - background-color: #2d2d2d; - border: 1px solid #444444; - padding: 10px; - margin: 10px 0 10px 0; - font-family: "Andale Mono", monospace; - font-size: .85em; - color: #e0e0e0; -} - -pre { - background-color: #2d2d2d; - border: 1px solid #444444; - padding: 10px; - margin: 10px 0 10px 0; - font-family: "Andale Mono", monospace; - color: #e0e0e0; -} - - -table.index { border: 1px #00007f; } -table.index td { text-align: left; vertical-align: top; } - -#container { - margin-left: 1em; - margin-right: 1em; - background-color: #242424; -} - -#product { - text-align: center; - border-bottom: 1px solid #cccccc; - background-color: #3a3a3a; -} - -#product big { - font-size: 2em; -} - -#main { - background-color: #131313; - border-left: 2px solid #cccccc; -} - -#navigation { - float: left; - width: 14em; - vertical-align: top; - background-color: #2d2d2d; - overflow: visible; -} - -#navigation h2 { - background-color: #333333; - font-size: 1.1em; - color: #ffffff; - text-align: left; - padding: 0.2em; - border-top: 1px solid #444444; - border-bottom: 1px solid #444444; -} - -#navigation ul -{ - font-size: 1em; - list-style-type: none; - margin: 1px 1px 10px 1px; -} - -#navigation li { - text-indent: -1em; - display: block; - margin: 3px 0px 0px 22px; -} - -#navigation li li a { - margin: 0px 3px 0px -1em; -} - -#content { - margin-left: 14em; - width: 40em; - padding: 1em; - border-left: 2px solid #444444; - border-right: 2px solid #444444; - background-color: #242424; -} - -#about { - clear: both; - padding: 5px; - border-top: 2px solid #cccccc; - background-color: #202020; -} - -@media print { - body { - font: 12pt "Times New Roman", "TimeNR", Times, serif; - } - a { font-weight: bold; color: #004080; text-decoration: underline; } - - #main { - background-color: #1d1a1a; - border-left: 0px; - } - - #container { - margin-left: 2%; - margin-right: 2%; - background-color: #1b1a1a; - } - - #content { - padding: 1em; - background-color: #1d1a1a; - } - - #navigation { - display: none; - } - pre.example { - font-family: "Andale Mono", monospace; - font-size: 10pt; - page-break-inside: avoid; - } -} - -table.module_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #444444; -} -table.module_list td.name { background-color: #333333; } -table.module_list td.summary { width: 100%; } - -table.file_list { - border-width: 1px; - border-style: solid; - border-color: #444444; - border-collapse: collapse; -} -table.file_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #444444; -} - -table.file_list td.name { background-color: #333333; } - -table.file_list td.summary { width: 100%; } - -table.function_list { - border-width: 1px; - border-style: solid; - border-color: #444444; - border-collapse: collapse; -} -table.function_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #444444; -} - -table.function_list td.name { background-color: #333333; } - -table.function_list td.summary { width: 100%; } - -table.table_list { - border-width: 1px; - border-style: solid; - border-color: #444444; - border-collapse: collapse; -} -table.table_list td { - border-width: 1px; - padding: 3px; - border-style: solid; - border-color: #444444; -} - -table.table_list td.name { background-color: #333333; } - -table.table_list td.summary { width: 100%; } - -dl.table dt, dl.function dt {border-top: 1px solid #444444; padding-top: 1em;} -dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} -dl.table h3, dl.function h3 {font-size: .95em;} \ No newline at end of file diff --git a/manual.md b/manual.md deleted file mode 100644 index 15cd6ef..0000000 --- a/manual.md +++ /dev/null @@ -1 +0,0 @@ -Comming soon \ No newline at end of file diff --git a/markdown.lua b/markdown.lua new file mode 100644 index 0000000..fdff881 --- /dev/null +++ b/markdown.lua @@ -0,0 +1,316 @@ +local markdown = { + blocks = {} +} + +local commentTypes = { + "module", + "param", + "return", + "usage", + "function", + "local", + "shortDescription", + "property" +} + +local function extractComment(line) + local tripleContent = line:match("^%-%-%-%s*(.*)") + if tripleContent then + return tripleContent, true + end + + local doubleContent = line:match("^%-%- %s*(.*)") + if doubleContent then + return doubleContent, false + end + + return nil, false +end + +local function getCommentType(comment) + for _, pattern in pairs(commentTypes) do + if comment:match("^@"..pattern) then + local content = comment:sub(#pattern + 2):gsub("^%s*", "") + return pattern, content + end + end + + return "desc", comment +end + +local function hasBlockContent(block) + for key, _ in pairs(block) do + if(key~="type")and(key~="desc")then + return true + end + end + if(#block.desc > 0)then + return true + end + + return false +end + +local function getFunctionName(line) + local pattern = "^function%s+([%w_%.:]-)%s*%(" + return line:match(pattern) +end + +function markdown.parse(content) + local blocks = {} + local properties = {} + local events = {} + local currentBlock = {type = "comment", desc = {}} + + for line in content:gsub("\r\n", "\n"):gmatch("([^\n]*)\n?") do + if line:match("^%s*$") or line == "" then + if hasBlockContent(currentBlock) then + table.insert(blocks, currentBlock) + currentBlock = {type = "comment", desc = {}} + end + else + local comment, isDoc = extractComment(line) + if comment then + local commentType, value = getCommentType(comment) + if(commentType == "desc") then + currentBlock.usageIsActive = false + table.insert(currentBlock.desc, value) + else + if(commentType == "module")then + currentBlock.usageIsActive = false + currentBlock.type = "module" + currentBlock.moduleName = value + end + if(commentType == "usage")then + currentBlock.usage = currentBlock.usage or {} + if(currentBlock.usageIsActive~=true)then + currentBlock.usageIsActive = true + table.insert(currentBlock.usage, {line=#currentBlock.desc+1, content={value}}) + else + table.insert(currentBlock.usage[#currentBlock.usage].content, value) + end + elseif(commentType == "shortDescription")then + currentBlock.usageIsActive = false + currentBlock.shortDescription = value + elseif(commentType == "property")then + currentBlock = {type = "comment", desc = {}} + table.insert(properties, value) + elseif(commentType == "event")then + currentBlock = {type = "comment", desc = {}} + table.insert(events, value) + else + currentBlock.usageIsActive = false + currentBlock[commentType] = currentBlock[commentType] or {} + table.insert(currentBlock[commentType], value) + end + + + + end + else + local funcName = getFunctionName(line) + if funcName then + currentBlock.func = funcName + currentBlock.type = "function" + end + end + end + end + + if hasBlockContent(currentBlock) then + table.insert(blocks, currentBlock) + end + + local functionBlocks = {} + local otherBlocks = {} + + for _, block in ipairs(blocks) do + if block.type == "function" then + table.insert(functionBlocks, block) + else + table.insert(otherBlocks, block) + end + end + + table.sort(functionBlocks, function(a, b) + return a.func < b.func + end) + + markdown.blocks = {properties = properties, events = events} + for _, block in ipairs(otherBlocks) do + table.insert(markdown.blocks, block) + end + for _, block in ipairs(functionBlocks) do + table.insert(markdown.blocks, block) + end +end + +local function markdownFunction(block) + local fOutput = "## " .. block.func .. "(" + local output = "" + if block.desc then + for _, line in pairs(block.desc) do + output = output .. line .. "\n" + end + end + if(block.param)then + output = output .. "\n### Parameters\n" + for _, line in pairs(block.param) do + local name, paramType, desc = line:match("([^%s]+)%s+([^%s]+)%s+(.*)") + fOutput = fOutput .. name .. (block.param[#block.param] == line and "" or ", ") + if name:match("%?$") then + name = name:sub(1, -2) + output = output .. string.format("* `%s` *(optional)* `%s` %s\n", name, paramType, desc) + else + output = output .. string.format("* `%s` `%s` %s\n", name, paramType, desc) + end + end + end + if(block["return"])then + output = output .. "\n### Returns\n" + for _, line in pairs(block["return"]) do + local name, paramType, desc = line:match("([^%s]+)%s+([^%s]+)%s+(.*)") + output = output .. string.format("* `%s` `%s` %s\n", name, paramType, desc) + end + end + if(block.usage)then + for k,v in pairs(block.usage) do + output = output .. "\n### Usage\n ```lua\n" + for _, line in pairs(v.content) do + output = output .. line .. "\n" + end + output = output .. "```\n" + end + end + + output = fOutput ..")\n" .. output .. "\n" + return output +end + +local function markdownProperties() + if(#markdown.blocks.properties<=0)then + return "" + end + local output = "\n## Properties\n\n|Property|Type|Default|Description|\n|---|---|---|---|\n" + for _, block in pairs(markdown.blocks.properties) 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" then + if(block.event~=nil)then + for _, line in pairs(block.event) do + output = output .. "* " .. line .. "\n" + end + end + end + end + return output +end + +local function markdownModuleFunctions() + if(#markdown.blocks<=0)then + return "" + end + local output = "\n## Functions\n\n|Method|Returns|Description|\n|---|---|---|\n" + for _, block in pairs(markdown.blocks) do + if block.type == "function" then + output = output .. "|[" .. block.func .. "](#" .. block.func .. ")|" + if(block["return"]~=nil)then + local returnType = block["return"][1]:match("^(%S+)") + output = output .. returnType.."|" + else + output = output .. "-|" + end + if(block.shortDescription~=nil)then + output = output .. block.shortDescription.."\n" + else + output = output .. "\n" + end + end + end + return output +end + +local function markdownModule(block) + local output = "# ".. block.moduleName.."\n" + if(block.usage~=nil)then + if(#block.usage > 0)then + for k,v in pairs(block.usage) do + local _output = "\n### Usage\n ```lua\n" + for _, line in pairs(v.content) do + _output = _output .. line .. "\n" + end + _output = _output .. "```\n" + table.insert(block.desc, v.line, _output) + end + end + end + for _, line in pairs(block.desc) do + output = output .. line .. "\n" + end + + output = output .. markdownProperties() + output = output .. markdownEvents() + output = output .. markdownModuleFunctions(block) + output = output .. "\n" + return output +end + +function markdown.makeMarkdown() + local output = "" + for _, block in pairs(markdown.blocks) do + if block.type == "function" then + output = output .. markdownFunction(block) + elseif block.type == "comment" then + for _, line in pairs(block.desc) do + output = output .. line .. "\n" + end + elseif block.type == "module" then + output = output .. markdownModule(block) + end + end + + return output +end + +function markdown.parseFile(source) + local file = io.open(source, "r") + if not file then + error("File not found: " .. source) + end + + local input = file:read("*a") + file:close() + + return markdown.parse(input) +end + +function markdown.saveToFile(source, output) + local file = io.open(source, "w") + if not file then + error("Could not open file for writing: " .. source) + end + + file:write(output) + file:close() +end + +local args = {...} +if args[1]~= nil and args[2]~= nil then + local source = args[1] + local output = args[2] + markdown.parseFile(source) + local md = markdown.makeMarkdown() + markdown.saveToFile(output, md) +end + +return markdown diff --git a/src/elements/BaseElement.lua b/src/elements/BaseElement.lua index aabfc63..9f3c79f 100644 --- a/src/elements/BaseElement.lua +++ b/src/elements/BaseElement.lua @@ -1,12 +1,22 @@ -local PropertySystem = require("propertySystem") -- muss geƤndert werden. +local PropertySystem = require("propertySystem") +--- The base class for all UI elements in Basalt +-- @module BaseElement local BaseElement = setmetatable({}, PropertySystem) BaseElement.__index = BaseElement BaseElement._events = {} +--- @property type string BaseElement The type identifier of the element BaseElement.defineProperty(BaseElement, "type", {default = "BaseElement", type = "string"}) + +--- @property eventCallbacks table {} Table containing all registered event callbacks BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"}) +--- Creates a new BaseElement instance +--- @param id string The unique identifier for this element +--- @param basalt table The basalt instance +--- @return table The newly created BaseElement instance +--- @usage local element = BaseElement.new("myId", basalt) function BaseElement.new(id, basalt) local self = setmetatable({}, BaseElement):__init() self:init(id, basalt) @@ -14,6 +24,10 @@ function BaseElement.new(id, basalt) return self end +--- Initializes the BaseElement instance +--- @param id string The unique identifier for this element +--- @param basalt table The basalt instance +--- @return table self The initialized instance function BaseElement:init(id, basalt) self.id = id self.basalt = basalt @@ -32,6 +46,10 @@ function BaseElement:init(id, basalt) return self end +--- Registers an event that this class can listen to +--- @param class table The class to add the event to +--- @param eventName string The name of the event to register +--- @usage BaseElement.listenTo(MyClass, "mouse_click") function BaseElement.listenTo(class, eventName) if not class._events then class._events = {} @@ -39,6 +57,11 @@ function BaseElement.listenTo(class, eventName) class._events[eventName] = true end +--- Enables or disables event listening for a specific event +--- @param eventName string The name of the event to listen for +--- @param enable? boolean Whether to enable or disable the event (default: true) +--- @return table self The BaseElement instance +--- @usage element:listenEvent("mouse_click", true) function BaseElement:listenEvent(eventName, enable) enable = enable ~= false if enable ~= (self._registeredEvents[eventName] or false) then @@ -57,6 +80,11 @@ function BaseElement:listenEvent(eventName, enable) return self end +--- Registers a callback function for an event +--- @param event string The event to register the callback for +--- @param callback function The callback function to register +--- @return table self The BaseElement instance +--- @usage element:registerCallback("mouse_click", function(self, ...) end) function BaseElement:registerCallback(event, callback) if not self._registeredEvents[event] then self:listenEvent(event, true) @@ -70,6 +98,11 @@ function BaseElement:registerCallback(event, callback) return self end +--- Triggers an event and calls all registered callbacks +--- @param event string The event to fire +--- @param ... any Additional arguments to pass to the callbacks +--- @return table self The BaseElement instance +--- @usage element:fireEvent("mouse_click", 1, 2) function BaseElement:fireEvent(event, ...) if self._values.eventCallbacks[event] then for _, callback in ipairs(self._values.eventCallbacks[event]) do @@ -80,6 +113,8 @@ function BaseElement:fireEvent(event, ...) return self end +--- Requests a render update for this element +--- @usage element:updateRender() function BaseElement:updateRender() if(self.parent) then self.parent:updateRender() diff --git a/src/main.lua b/src/main.lua index 68fb704..878542e 100644 --- a/src/main.lua +++ b/src/main.lua @@ -1,25 +1,12 @@ ---- Basalt UI Framework main module. --- This is the main entry point for the Basalt UI Framework. --- It provides functions for creating and managing UI elements and handling events. --- @module basalt --- @usage --- local basalt = require("basalt") --- local mainFrame = basalt.createFrame() --- mainFrame:show() --- basalt.run() - local elementManager = require("elementManager") -local expect = require("libraries/expect") local errorManager = require("errorManager") ---- The main Basalt instance --- Contains all core functionality and management functions --- @type Basalt --- @field traceback boolean Enable/disable error tracing --- @field _events table Internal events storage --- @field _schedule table Internal schedule storage --- @field _plugins table Plugins storage --- @field LOGGER table Logging instance +--- This is the UI Manager and the starting point for your project. The following functions allow you to influence the default behavior of Basalt. +--- +--- 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 local basalt = {} basalt.traceback = true basalt._events = {} @@ -31,6 +18,7 @@ local mainFrame = nil local updaterActive = false --- Creates and returns a new UI element of the specified type +--- @shortDescription Creates a new UI element --- @param type string The type of element to create (e.g. "Button", "Label", "BaseFrame") --- @param id? string Optional unique identifier for the element --- @return table element The created element instance @@ -96,8 +84,7 @@ function basalt.removeSchedule(id) basalt._schedule[id] = nil end ---- Internal event handler ---- @local +--- @local Internal event handler local function updateEvent(event, ...) if(event=="terminate")then basalt.stop() end @@ -120,8 +107,7 @@ local function updateEvent(event, ...) end end ---- Internal render function ---- @local +--- @local Internal render function local function renderFrames() if(mainFrame)then mainFrame:render()