removed scrollbar from tables

added enabled property
This commit is contained in:
Robert Jelic
2025-06-22 04:17:14 +02:00
parent 1b467c4d4a
commit 8fd37ee1fe
9 changed files with 291 additions and 222 deletions

1
.gitignore vendored
View File

@@ -9,3 +9,4 @@ testWorkflows
todo.txt
Flexbox2.lua
markdown2.lua
BasaltDoc

View File

@@ -31,6 +31,9 @@ BaseElement.defineProperty(BaseElement, "name", {default = "", type = "string"})
--- @property eventCallbacks table BaseElement The event callbacks for the element
BaseElement.defineProperty(BaseElement, "eventCallbacks", {default = {}, type = "table"})
--- @property enabled boolean BaseElement Whether the element is enabled or not
BaseElement.defineProperty(BaseElement, "enabled", {default = true, type = "boolean" })
--- Registers a new event listener for the element (on class level)
--- @shortDescription Registers a new event listener for the element (on class level)
--- @param class table The class to register
@@ -215,6 +218,9 @@ end
--- @return boolean? handled Whether the event was handled
--- @protected
function BaseElement:dispatchEvent(event, ...)
if self.get("enabled") == false then
return false
end
if self[event] then
return self[event](self, ...)
end

View File

@@ -216,7 +216,7 @@ function Table:render()
local finalText = string.sub(paddedText, 1, col.width)
local finalForeground = string.rep(tHex[self.get("foreground")], #finalText)
local finalBackground = string.rep(tHex[bg], #finalText)
self:blit(currentX, y, finalText, finalForeground, finalBackground)
currentX = currentX + col.width
end
@@ -226,27 +226,6 @@ function Table:render()
string.rep(tHex[self.get("background")], self.get("width")))
end
end
if #data > height - 2 then
local scrollbarHeight = height - 2
local thumbSize = math.max(1, math.floor(scrollbarHeight * (height - 2) / #data))
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
end
for y = 2, height do
self:blit(self.get("width"), y, "\127", tHex[colors.gray], tHex[colors.gray])
end
for y = thumbPos, math.min(height, thumbPos + thumbSize - 1) do
self:blit(self.get("width"), y, "\127", tHex[colors.white], tHex[colors.white])
end
end
end
return Table

View File

@@ -99,7 +99,7 @@ VisualElement.registerEventCallback(VisualElement, "ClickUp", "mouse_up", "mouse
VisualElement.registerEventCallback(VisualElement, "Drag", "mouse_drag", "mouse_click", "mouse_up")
VisualElement.registerEventCallback(VisualElement, "Scroll", "mouse_scroll")
VisualElement.registerEventCallback(VisualElement, "Enter", "mouse_enter", "mouse_move")
VisualElement.registerEventCallback(VisualElement, "LeEave", "mouse_leave", "mouse_move")
VisualElement.registerEventCallback(VisualElement, "Leave", "mouse_leave", "mouse_move")
VisualElement.registerEventCallback(VisualElement, "Focus", "focus", "blur")
VisualElement.registerEventCallback(VisualElement, "Blur", "blur", "focus")
VisualElement.registerEventCallback(VisualElement, "Key", "key", "key_up")

View File

@@ -26,6 +26,7 @@ function Button.new()
return self
end
--- Initializes the Button instance
--- @shortDescription Initializes the Button instance
--- @param props table The properties to initialize the element with
--- @param basalt table The basalt instance

View File

@@ -1,101 +1,81 @@
local CommentExtractor = {}
--- Extracts comments with their associated code context
-- @param lines table The lines of the Lua file as a table of strings.
-- @return table A table containing comment blocks with context.
function CommentExtractor.extractComments(lines)
--- Extracts comment blocks that belong together
function CommentExtractor.extractBlocks(lines)
local blocks = {}
local currentCommentBlock = {}
local i = 1
local currentBlock = {
comments = {},
codeContext = nil
}
local i = 1
while i <= #lines do
local line = lines[i]:match("^%s*(.*)") -- Trim leading whitespace
local line = lines[i]
local trimmed = line:match("^%s*(.-)%s*$")
-- Check if this is a comment line
if line:find("^%-%-%-") or line:find("^%-%-") then
table.insert(currentCommentBlock, line)
elseif #currentCommentBlock > 0 then
-- We have accumulated comments, check if next non-empty line is code
local codeContext = nil
local j = i
-- Skip empty lines to find the actual code
while j <= #lines and lines[j]:match("^%s*$") do
j = j + 1
if trimmed:match("^%-%-%-") or trimmed:match("^%-%-") then
table.insert(currentBlock.comments, trimmed)
elseif #currentBlock.comments > 0 then
-- We have comments, now look for the code that follows
local codeLineIndex = CommentExtractor.findNextCodeLine(lines, i)
if codeLineIndex then
local codeLine = lines[codeLineIndex]:match("^%s*(.-)%s*$")
currentBlock.codeContext = CommentExtractor.analyzeCode(codeLine, codeLineIndex)
end
if j <= #lines then
local codeLine = lines[j]:match("^%s*(.*)")
-- Check if it's a function, class, property, etc.
if codeLine:find("^function") or
codeLine:find("^local function") or
codeLine:find("^local%s+%w+%s*=") or
codeLine:find("^%w+%.%w+") then
codeContext = {
type = CommentExtractor.getCodeType(codeLine),
name = CommentExtractor.extractName(codeLine),
line = codeLine,
lineNumber = j
}
end
end
-- Add the comment block with its context
table.insert(blocks, {
comments = currentCommentBlock,
context = codeContext
})
currentCommentBlock = {}
-- Save this block and start a new one
table.insert(blocks, currentBlock)
currentBlock = {comments = {}, codeContext = nil}
end
i = i + 1
end
-- Handle any remaining comments
if #currentCommentBlock > 0 then
table.insert(blocks, {
comments = currentCommentBlock,
context = nil
})
-- Handle remaining comments
if #currentBlock.comments > 0 then
table.insert(blocks, currentBlock)
end
return blocks
end
--- Determines the type of code (function, class, property, etc.)
function CommentExtractor.getCodeType(codeLine)
if codeLine:find("^function") or codeLine:find("^local function") then
return "function"
elseif codeLine:find("^local%s+%w+%s*=%s*setmetatable") then
return "class"
elseif codeLine:find("^local%s+%w+%s*=") then
return "variable"
elseif codeLine:find("^%w+%.defineProperty") then
return "property_definition"
else
return "unknown"
--- Find the next non-empty code line
function CommentExtractor.findNextCodeLine(lines, startIndex)
for i = startIndex, #lines do
local trimmed = lines[i]:match("^%s*(.-)%s*$")
if trimmed ~= "" and not trimmed:match("^%-%-") then
return i
end
end
return nil
end
--- Extracts the name from a code line
function CommentExtractor.extractName(codeLine)
--- Analyze what kind of code this is
function CommentExtractor.analyzeCode(codeLine, lineNumber)
-- Function patterns
local funcName = codeLine:match("^function%s+([%w%.%:]+)")
if funcName then return funcName end
if codeLine:match("^function%s+([%w%.%:]+)") then
local name = codeLine:match("^function%s+([%w%.%:]+)")
return {type = "function", name = name, line = codeLine, lineNumber = lineNumber}
end
local localFuncName = codeLine:match("^local%s+function%s+([%w%.%:]+)")
if localFuncName then return localFuncName end
if codeLine:match("^local%s+function%s+([%w%.%:]+)") then
local name = codeLine:match("^local%s+function%s+([%w%.%:]+)")
return {type = "function", name = name, line = codeLine, lineNumber = lineNumber}
end
-- Variable/class patterns
local varName = codeLine:match("^local%s+([%w_]+)%s*=")
if varName then return varName end
-- Class/variable patterns
if codeLine:match("^local%s+([%w_]+)%s*=%s*setmetatable") then
local name = codeLine:match("^local%s+([%w_]+)%s*=")
return {type = "class", name = name, line = codeLine, lineNumber = lineNumber}
end
-- Method patterns
local methodName = codeLine:match("^([%w%.%:]+)%s*=")
if methodName then return methodName end
if codeLine:match("^local%s+([%w_]+)%s*=") then
local name = codeLine:match("^local%s+([%w_]+)%s*=")
return {type = "variable", name = name, line = codeLine, lineNumber = lineNumber}
end
return "unknown"
return {type = "unknown", name = "unknown", line = codeLine, lineNumber = lineNumber}
end
return CommentExtractor

View File

@@ -1,4 +1,5 @@
local CommentExtractor = require("parser.comment_extractor")
local TagParser = require("parser.tag_parser")
local MarkdownGenerator = require("parser.markdown_generator")
local Parser = {}
@@ -9,21 +10,23 @@ function Parser.extractComments(content)
for line in content:gmatch("[^\r\n]+") do
table.insert(lines, line)
end
return CommentExtractor.extractComments(lines)
return CommentExtractor.extractBlocks(lines)
end
--- Generate markdown from comment blocks
function Parser.generateMarkdown(commentBlocks)
local parsedBlocks = {}
local markdown = {}
-- Parse each block using the appropriate parser
-- Parse each block and generate markdown
for _, block in ipairs(commentBlocks) do
local parsedBlock = MarkdownGenerator.parseBlock(block)
table.insert(parsedBlocks, parsedBlock)
local tags = TagParser.parseAllTags(block.comments)
local blockMarkdown = MarkdownGenerator.generateBlock(block, tags)
if blockMarkdown and blockMarkdown ~= "" then
table.insert(markdown, blockMarkdown)
end
end
-- Generate markdown from parsed blocks
return MarkdownGenerator.generateMarkdown(parsedBlocks)
return table.concat(markdown, "\n\n")
end
return Parser

View File

@@ -1,142 +1,143 @@
local markdownGenerator = {}
local TagParserRegistry = require("parser.tag_parser_registry")
local MarkdownGenerator = {}
--- Determines which block parser should handle a given block
--- @param block table The comment block with context
--- @return string|nil The block type that can handle this block
function markdownGenerator.detectBlockType(block)
local blockParsers = TagParserRegistry.getAllBlocks()
for blockType, parser in pairs(blockParsers) do
if parser.canParse and parser.canParse(block) then
return blockType
end
--- Generate markdown for a block
function MarkdownGenerator.generateBlock(block, tags)
if not block.codeContext then
return MarkdownGenerator.generateStandaloneComment(tags)
end
return nil -- No specific block parser found, use generic parsing
end
--- Parses a block using the appropriate block parser
--- @param block table The comment block to parse
--- @return table The parsed block data
function markdownGenerator.parseBlock(block)
local blockType = markdownGenerator.detectBlockType(block)
if blockType then
local parser = TagParserRegistry.getBlock(blockType)
return parser.parse(block)
if block.codeContext.type == "function" then
return MarkdownGenerator.generateFunction(block.codeContext, tags)
elseif block.codeContext.type == "class" then
return MarkdownGenerator.generateClass(block.codeContext, tags)
elseif block.codeContext.type == "variable" then
return MarkdownGenerator.generateVariable(block.codeContext, tags)
else
-- Generic parsing using individual tag parsers
return markdownGenerator.parseGenericBlock(block)
return MarkdownGenerator.generateGeneric(block.codeContext, tags)
end
end
--- Generic block parsing using individual tag parsers
--- @param block table The comment block to parse
--- @return table The parsed block data
function markdownGenerator.parseGenericBlock(block)
local parsedBlock = {
type = "generic",
tags = {},
content = {},
context = block.context
}
for _, line in ipairs(block.comments) do
local parsed = false
local tagParsers = TagParserRegistry.getAllTags()
-- Try each registered tag parser
for tagName, parser in pairs(tagParsers) do
local result = parser.parse(line)
if result then
table.insert(parsedBlock.tags, result)
parsed = true
break
end
end
-- If no tag parser matched, treat as regular content
if not parsed then
table.insert(parsedBlock.content, line)
end
end
return parsedBlock
end
--- Converts parsed blocks to markdown
--- @param parsedBlocks table Array of parsed blocks
--- @return string The generated markdown
function markdownGenerator.generateMarkdown(parsedBlocks)
local markdown = {}
for _, block in ipairs(parsedBlocks) do
if block.type == "function" then
table.insert(markdown, markdownGenerator.generateFunctionMarkdown(block))
else
table.insert(markdown, markdownGenerator.generateGenericMarkdown(block))
end
table.insert(markdown, "") -- Empty line between blocks
end
return table.concat(markdown, "\n")
end
--- Generate markdown for function blocks
--- @param functionBlock table The parsed function block
--- @return string The generated markdown
function markdownGenerator.generateFunctionMarkdown(functionBlock)
--- Generate markdown for function
function MarkdownGenerator.generateFunction(context, tags)
local md = {}
table.insert(md, string.format("## Function: %s", functionBlock.name))
table.insert(md, string.format("### %s", context.name))
table.insert(md, "")
if functionBlock.shortDescription then
table.insert(md, string.format("**Description:** %s", functionBlock.shortDescription))
if tags.shortDescription then
table.insert(md, tags.shortDescription)
table.insert(md, "")
end
if #functionBlock.params > 0 then
if #tags.description > 0 then
table.insert(md, table.concat(tags.description, " "))
table.insert(md, "")
end
if #tags.params > 0 then
table.insert(md, "**Parameters:**")
for _, param in ipairs(functionBlock.params) do
table.insert(md, string.format("- `%s` (%s): %s", param.name, param.type, param.description))
for _, param in ipairs(tags.params) do
table.insert(md, string.format("- `%s` (%s): %s", param.name, param.dataType, param.description))
end
table.insert(md, "")
end
if #functionBlock.returns > 0 then
if #tags.returns > 0 then
table.insert(md, "**Returns:**")
for _, ret in ipairs(functionBlock.returns) do
table.insert(md, string.format("- `%s` (%s): %s", ret.name, ret.type, ret.description))
for _, ret in ipairs(tags.returns) do
table.insert(md, string.format("- `%s` (%s): %s", ret.name, ret.dataType, ret.description))
end
table.insert(md, "")
end
if functionBlock.visibility ~= "public" then
table.insert(md, string.format("**Visibility:** %s", functionBlock.visibility))
if tags.visibility ~= "public" then
table.insert(md, string.format("**Visibility:** %s", tags.visibility))
table.insert(md, "")
end
return table.concat(md, "\n")
end
--- Generate markdown for generic blocks
--- @param block table The parsed generic block
--- @return string The generated markdown
function markdownGenerator.generateGenericMarkdown(block)
--- Generate markdown for class
function MarkdownGenerator.generateClass(context, tags)
local md = {}
-- Generate markdown for tags
if #block.tags > 0 then
table.insert(md, "### Tags")
for _, tag in ipairs(block.tags) do
table.insert(md, string.format("- **%s**: %s", tag.name, tag.description))
end
table.insert(md, string.format("## Class: %s", context.name))
if tags.class and tags.class.parent then
table.insert(md, string.format("*Extends: %s*", tags.class.parent))
end
table.insert(md, "")
if tags.shortDescription then
table.insert(md, tags.shortDescription)
table.insert(md, "")
end
-- Generate markdown for content
if #block.content > 0 then
table.insert(md, "### Content")
table.insert(md, table.concat(block.content, "\n"))
if #tags.description > 0 then
table.insert(md, table.concat(tags.description, " "))
table.insert(md, "")
end
return table.concat(md, "\n\n")
return table.concat(md, "\n")
end
return markdownGenerator
--- Generate markdown for standalone comments or properties
function MarkdownGenerator.generateStandaloneComment(tags)
local md = {}
if #tags.properties > 0 then
for _, prop in ipairs(tags.properties) do
table.insert(md, string.format("**Property:** `%s` (%s) - %s", prop.name, prop.dataType, prop.description))
end
table.insert(md, "")
end
if #tags.description > 0 then
table.insert(md, table.concat(tags.description, " "))
table.insert(md, "")
end
return table.concat(md, "\n")
end
--- Generate markdown for variables
function MarkdownGenerator.generateVariable(context, tags)
local md = {}
table.insert(md, string.format("### %s", context.name))
table.insert(md, "")
if tags.shortDescription then
table.insert(md, tags.shortDescription)
table.insert(md, "")
end
if #tags.description > 0 then
table.insert(md, table.concat(tags.description, " "))
table.insert(md, "")
end
return table.concat(md, "\n")
end
--- Generate markdown for generic code
function MarkdownGenerator.generateGeneric(context, tags)
local md = {}
table.insert(md, string.format("### %s", context.name))
table.insert(md, "")
if tags.shortDescription then
table.insert(md, tags.shortDescription)
table.insert(md, "")
end
if #tags.description > 0 then
table.insert(md, table.concat(tags.description, " "))
table.insert(md, "")
end
return table.concat(md, "\n")
end
return MarkdownGenerator

View File

@@ -1,19 +1,117 @@
local tagParser = {}
local TagParser = {}
local function parseTag(tagLine)
local tag, content = tagLine:match("^%s*@(.-)%s*(.*)$")
return tag, content
end
function tagParser.parseTags(commentLines)
local tags = {}
--- Parse all tags from a list of comment lines
function TagParser.parseAllTags(commentLines)
local tags = {
shortDescription = nil,
description = {},
params = {},
returns = {},
visibility = "public",
properties = {},
class = nil,
other = {}
}
for _, line in ipairs(commentLines) do
local tag, content = parseTag(line)
if tag then
tags[tag] = content
local parsed = TagParser.parseSingleLine(line)
if parsed then
TagParser.addToTags(tags, parsed)
else
-- Regular description line
local desc = line:match("^%-*%s*(.+)$")
if desc and not desc:match("^@") then
table.insert(tags.description, desc)
end
end
end
return tags
end
return tagParser
--- Parse a single comment line for tags
function TagParser.parseSingleLine(line)
-- @shortDescription
local shortDesc = line:match("^%-*%s*@shortDescription%s+(.+)$")
if shortDesc then
return {type = "shortDescription", value = shortDesc}
end
-- @param name type description
local paramName, paramType, paramDesc = line:match("^%-*%s*@param%s+(%S+)%s+(%S+)%s*(.*)$")
if paramName then
return {
type = "param",
name = paramName,
dataType = paramType,
description = paramDesc or ""
}
end
-- @return type name description
local returnType, returnName, returnDesc = line:match("^%-*%s*@return%s+(%S+)%s+(%S+)%s*(.*)$")
if returnType then
return {
type = "return",
dataType = returnType,
name = returnName or "",
description = returnDesc or ""
}
end
-- @property name type description
local propName, propType, propDesc = line:match("^%-*%s*@property%s+(%S+)%s+(%S+)%s*(.*)$")
if propName then
return {
type = "property",
name = propName,
dataType = propType,
description = propDesc or ""
}
end
-- @class name : parent
local className, parentClass = line:match("^%-*%s*@class%s+(%S+)%s*:%s*(%S+)")
if not className then
className = line:match("^%-*%s*@class%s+(%S+)")
end
if className then
return {
type = "class",
name = className,
parent = parentClass or nil
}
end
-- Visibility tags
if line:match("^%-*%s*@private%s*$") then
return {type = "visibility", value = "private"}
end
if line:match("^%-*%s*@protected%s*$") then
return {type = "visibility", value = "protected"}
end
return nil
end
--- Add parsed tag to the tags collection
function TagParser.addToTags(tags, parsed)
if parsed.type == "shortDescription" then
tags.shortDescription = parsed.value
elseif parsed.type == "param" then
table.insert(tags.params, parsed)
elseif parsed.type == "return" then
table.insert(tags.returns, parsed)
elseif parsed.type == "property" then
table.insert(tags.properties, parsed)
elseif parsed.type == "class" then
tags.class = parsed
elseif parsed.type == "visibility" then
tags.visibility = parsed.value
else
table.insert(tags.other, parsed)
end
end
return TagParser