I found a need to reference functions that I've defined in the global scope so I added an index for top-level function/variable definitions in space-lua blocks. I literally just cobbled this together but thought it might be useful for others in its rough form.
Here's a simple widget:
lua = lua or {}
function lua.ref(name)
local refs = query[[from l = index.tag "lua" where l.name == name order by l.priority asc limit 1 select l.ref]]
if not some(refs) then
return widget.markdown("Lua object " .. name .. " not found")
end
return widget.markdown("[[" .. refs[1] .. "|" .. name .. "]]")
end
Example usage:
This a ref to ${lua.ref("lua.ref")}.
Here's the indexer: ${lua.ref("indexPageLua")}.
A handy command:
commands = commands or {}
function commands.luaPicker()
local refs = query[[from l = index.tag "lua" select {name=l.name, value=l.ref}]]
local result = editor.filterBox("Select:", refs)
if some(result) then
editor.navigate(result.value)
end
end
command.define {
name = "Navigate: Lua Picker",
run = commands.luaPicker,
}
And here's the page:index handler:
function table.extend(tbl, vals)
for _, val in ipairs(vals) do
table.insert(tbl, val)
end
return tbl
end
local function findNodes(tree, f)
if not tree then
return {}
end
if f(tree) then
return {tree}
end
if not tree.children then
return {}
end
local res = {}
for _, c in ipairs(tree.children) do
table.extend(res, findNodes(c, f))
end
return res
end
local function findSpaceLua(tree)
local codes = findNodes(tree, function(tree) return tree.type == "FencedCode" end)
local res = {}
for _, code in ipairs(codes) do
if some(findNodes(code, function(tree) return tree.type == "CodeInfo" and tree.children and tree.children[1].text == "space-lua" end)) then
table.extend(res, findNodes(code, function(tree) return tree.type == "CodeText" end))
end
end
return res
end
local function varName(var)
if var.name then
return var.name
end
if var.type == "PropertyAccess" then
return table.concat({varName(var.object), var.property}, ".")
end
print("Unknown variable type:", var)
end
function indexSpaceLua(codeText, page)
local text = codeText.children[1].text
local priority = string.matchRegex(text, "\\s*--+\\s*priority:\\s*(-?\\d+)")
if priority then
priority = math.tointeger(priority[2])
end
local tree = lua.parse(text)
local tags = {}
for _, stmt in ipairs(tree.statements) do
if stmt.type == "Function" then
table.insert(tags, {
tag = "lua",
page = page,
kind = stmt.type,
name = table.concat(stmt.name.propNames, "."),
priority = priority,
ref = page .. "@" .. tostring(stmt.ctx.from + codeText.from)
})
elseif stmt.type == "Assignment" then
for _, var in ipairs(stmt.variables) do
table.insert(tags, {
tag = "lua",
page = page,
kind = var.type,
name = varName(var),
priority = priority,
ref = page .. "@" .. tostring(var.ctx.from + codeText.from)
})
end
end
end
return tags
end
function indexPageLua(page, tree)
tree = tree or markdown.parseMarkdown(space.readPage(page))
local blocks = findSpaceLua(tree)
local allTags = {}
for _, block in ipairs(blocks) do
table.extend(allTags, indexSpaceLua(block, page))
end
return allTags
end
event.listen {
name = "page:index",
run = function(e)
index.indexObjects(e.data.name, indexPageLua(e.data.name, e.data.tree))
end
}