6 → 4 → 2 level,
2 → 4 → 6 level,
2 → 4 → 2 level,
6 → 4 → 6 level
header structures now should display correctly.
lua Query to enhance speed (especially for the Giant-Tree Picker)
Heading Picker
command.define({
name = "Navigate: Heading Picker",
key = "Ctrl-Shift-h",
run = function()
local headers = query[[
from index.tag "header"
where _.page == editor.getCurrentPage()
order by _.pos
]]
if #headers == 0 then
editor.flashNotification("No headings found")
return
end
local min_level = 10
for _, h in ipairs(headers) do
if h.level < min_level then min_level = h.level end
end
local items = {}
local stack = {}
local VERT = "│ "
local BLNK = " "
local TEE = "├─── "
local ELB = "└─── "
for i, h in ipairs(headers) do
local is_last = true
for j = i + 1, #headers do
if headers[j].level <= h.level then
if headers[j].level == h.level then is_last = false end
break
end
end
local rel_level = h.level - min_level + 1
while #stack > 0 and stack[#stack].level >= rel_level do
table.remove(stack)
end
local prefix = ""
for _, s in ipairs(stack) do
prefix = prefix .. (s.last and BLNK or VERT)
end
for k = #stack + 1, rel_level - 1 do
local has_deeper = false
for j = i + 1, #headers do
local target_level = min_level + k - 1
if headers[j].level == target_level then
has_deeper = true
break
elseif headers[j].level < target_level then
break
end
end
prefix = prefix .. (has_deeper and VERT or BLNK)
end
table.insert(items, {
name = prefix .. (is_last and ELB or TEE) .. h.name,
ref = h.ref
})
table.insert(stack, { level = rel_level, last = is_last })
end
local selection = editor.filterBox("🤏 Pick", items, "Select a Header...", "a Header")
if selection then
editor.navigate(selection.ref)
editor.invokeCommand("Navigate: Center Cursor")
end
end
})
Tree-Tree Picker
(Page Picker → Heading Picker)
local pageTreePicker
local VERT = "│ "
local BLNK = " "
local TEE = "├─── "
local ELB = "└─── "
local function pickHeadings(pageName)
local text = space.readPage(pageName)
if not text then
editor.flashNotification("Could not read page: " .. pageName)
return
end
local nodes = query[[
from index.tag "header"
where _.page == pageName
order by _.pos
]]
if #nodes == 0 then
editor.navigate({ page = pageName })
editor.invokeCommand("Navigate: Center Cursor")
return
end
local min_level = 10
for _, n in ipairs(nodes) do
if n.level < min_level then min_level = n.level end
end
local last_flags = {}
for i = 1, #nodes do
local L = nodes[i].level
local is_last = true
for j = i + 1, #nodes do
if nodes[j].level <= L then
if nodes[j].level == L then
is_last = false
else
is_last = true
end
break
end
end
last_flags[i] = is_last
end
local items = {}
local stack = {}
table.insert(items, {
name = ".",
description = pageName,
pos = 0,
})
for i = 1, #nodes do
local node = nodes[i]
local L = node.level - min_level + 1
local is_last = last_flags[i]
while #stack > 0 and stack[#stack].level >= L do
table.remove(stack)
end
local prefix = ""
for d = 1, #stack do
prefix = prefix .. (stack[d].last and BLNK or VERT)
end
for k = #stack + 1, L - 1 do
local has_deeper = false
for j = i + 1, #nodes do
local next_L = nodes[j].level - min_level + 1
if next_L == k then
has_deeper = true
break
elseif next_L < k then
break
end
end
prefix = prefix .. (has_deeper and VERT or BLNK)
end
local path_parts = {}
for _, s in ipairs(stack) do
table.insert(path_parts, s.text)
end
table.insert(path_parts, node.name)
local full_path = table.concat(path_parts, " > ")
local elbow = is_last and ELB or TEE
local label = prefix .. elbow .. node.name
table.insert(items, {
name = label,
description = full_path,
pos = node.pos,
})
table.insert(stack, { level = L, last = is_last, text = node.name })
end
local result = editor.filterBox(pageName .. "#", items, "Select a Header...", "Heading Picker")
if result then
local pos = result.pos
if not pos and result.value and result.value.pos then
pos = result.value.pos
end
if pos == 0 then
editor.navigate({ page = pageName })
elseif pos then
editor.navigate({ page = pageName, pos = pos })
end
editor.invokeCommand("Navigate: Center Cursor")
else
return pageTreePicker()
end
end
pageTreePicker = function()
local pages = space.listPages()
local path_map = {}
local real_pages = {}
for _, page in ipairs(pages) do
real_pages[page.name] = true
end
for _, page in ipairs(pages) do
local parts = {}
for part in string.gmatch(page.name, "[^/]+") do
table.insert(parts, part)
local current_path = table.concat(parts, "/")
if not path_map[current_path] then
path_map[current_path] = {
name = current_path,
text = part,
level = #parts,
is_real = false,
}
end
end
end
for path, _ in pairs(real_pages) do
if path_map[path] then
path_map[path].is_real = true
end
end
local nodes = {}
for _, node in pairs(path_map) do
table.insert(nodes, node)
end
table.sort(nodes, function(a, b)
return a.name < b.name
end)
if #nodes == 0 then
editor.flashNotification("No pages found")
return
end
local last_flags = {}
for i = 1, #nodes do
local L = nodes[i].level
local is_last = true
for j = i + 1, #nodes do
local next_L = nodes[j].level
if next_L == L then
is_last = false
break
elseif next_L < L then
is_last = true
break
end
end
last_flags[i] = is_last
end
local items = {}
local stack = {}
for i = 1, #nodes do
local node = nodes[i]
local L = node.level
local is_last = last_flags[i]
while #stack >= L do
table.remove(stack)
end
local prefix = ""
for d = 1, #stack do
prefix = prefix .. (stack[d].last and BLNK or VERT)
end
for _ = #stack + 1, L - 1 do
prefix = prefix .. BLNK
end
local elbow = is_last and ELB or TEE
local display_text = node.text
local desc = node.name
if not node.is_real then
display_text = display_text .. "/"
desc = desc .. "/"
end
local label = prefix .. elbow .. display_text
table.insert(items, {
name = label,
description = desc,
value = {
page = node.name,
is_real = node.is_real,
},
})
table.insert(stack, { level = L, last = is_last })
end
local result = editor.filterBox("🤏 Pick:", items, "Select a Page...", "Page Tree")
if result then
local selection = result.value or result
if type(selection) ~= "table" then
if selection then pickHeadings(selection) end
return
end
local page_name = selection.page
local is_real = selection.is_real
if page_name then
if is_real then
pickHeadings(page_name)
else
editor.flashNotification("Folder selected. Creating page: " .. page_name)
editor.navigate({ page = page_name })
end
end
end
end
command.define({
name = "Navigate: Tree-Tree Picker",
key = "Shift-Alt-e",
run = function() pageTreePicker() end,
})
Giant-Tree Picker
(Page-Heading Picker)
local VERT = "│ "
local BLNK = " "
local TEE = "├─── "
local ELB = "└─── "
local function unifiedTreePicker()
local pages = space.listPages()
local path_map = {}
local real_pages = {}
for _, page in ipairs(pages) do
real_pages[page.name] = true
end
for _, page in ipairs(pages) do
local parts = {}
for part in string.gmatch(page.name, "[^/]+") do
table.insert(parts, part)
local current_path = table.concat(parts, "/")
if not path_map[current_path] then
path_map[current_path] = {
name = current_path,
text = part,
level = #parts,
is_real = false,
type = "folder"
}
end
end
end
for path, _ in pairs(real_pages) do
if path_map[path] then
path_map[path].is_real = true
path_map[path].type = "page"
end
end
local sorted_nodes = {}
for _, node in pairs(path_map) do
table.insert(sorted_nodes, node)
end
table.sort(sorted_nodes, function(a, b)
return a.name < b.name
end)
if #sorted_nodes == 0 then
editor.flashNotification("No pages found")
return
end
local all_headers = query[[
from index.tag "header"
order by _.page, _.pos
]]
local headers_by_page = {}
for _, h in ipairs(all_headers or {}) do
local p = h.page
if p and h.name and h.name ~= "" then
local bucket = headers_by_page[p]
if not bucket then
bucket = {}
headers_by_page[p] = bucket
end
table.insert(bucket, {
level = h.level or 1,
text = h.name,
pos = h.pos or 0
})
end
end
local final_nodes = {}
for _, node in ipairs(sorted_nodes) do
table.insert(final_nodes, node)
if node.is_real then
local headings = headers_by_page[node.name]
if headings and #headings > 0 then
local min_level = 10
for _, h in ipairs(headings) do
if h.level and h.level < min_level then
min_level = h.level
end
end
local heading_stack = {}
for _, h in ipairs(headings) do
local hlevel = h.level or min_level
while #heading_stack > 0 and heading_stack[#heading_stack].level >= hlevel do
table.remove(heading_stack)
end
table.insert(heading_stack, { level = hlevel, text = h.text })
local path_parts = { node.name }
for _, stack_item in ipairs(heading_stack) do
table.insert(path_parts, stack_item.text)
end
local full_path_desc = table.concat(path_parts, ">")
local relative_level = hlevel - min_level + 1
local absolute_level = node.level + relative_level
table.insert(final_nodes, {
name = node.name,
text = h.text,
level = absolute_level,
is_real = false,
type = "heading",
pos = h.pos,
page_name = node.name,
full_desc = full_path_desc
})
end
end
end
end
local last_flags = {}
local total = #final_nodes
for i = 1, total do
local L = final_nodes[i].level
local is_last = true
for j = i + 1, total do
local next_L = final_nodes[j].level
if next_L == L then
is_last = false
break
elseif next_L < L then
is_last = true
break
end
end
last_flags[i] = is_last
end
local items = {}
local stack = {}
for i = 1, total do
local node = final_nodes[i]
local L = node.level
local is_last = last_flags[i]
while #stack > 0 and stack[#stack].level >= L do
table.remove(stack)
end
local prefix = ""
for d = 1, #stack do
prefix = prefix .. (stack[d].last and BLNK or VERT)
end
for k = #stack + 1, L - 1 do
local has_deeper = false
for j = i + 1, total do
local next_L = final_nodes[j].level
if next_L == k then
has_deeper = true
break
elseif next_L < k then
break
end
end
prefix = prefix .. (has_deeper and VERT or BLNK)
end
local elbow = is_last and ELB or TEE
local display_text = node.text
local desc = ""
if node.type == "folder" then
display_text = display_text .. "/"
desc = node.name .. "/"
elseif node.type == "page" then
desc = node.name
elseif node.type == "heading" then
desc = node.full_desc
end
local label = prefix .. elbow .. display_text
table.insert(items, {
name = label,
description = desc,
value = {
page = node.page_name or node.name,
pos = node.pos,
type = node.type
}
})
table.insert(stack, { level = L, last = is_last })
end
local result = editor.filterBox("🤏 Pick:", items, "Select Page or Heading...", "Unified Tree")
if result then
local selection = result.value or result
if type(selection) ~= "table" then
return
end
local page_name = selection.page
local pos = selection.pos
local node_type = selection.type
if node_type == "folder" then
editor.flashNotification("Folder selected. Creating/Going to page: " .. page_name)
editor.navigate({ page = page_name })
elseif node_type == "page" or node_type == "heading" then
if pos and pos > 0 then
editor.navigate({ page = page_name, pos = pos })
else
editor.navigate({ page = page_name })
end
editor.invokeCommand("Navigate: Center Cursor")
end
end
end
command.define({
name = "Navigate: Tree-Tree Picker",
key = "Shift-Alt-e",
run = function() unifiedTreePicker() end
})