Some useful JSON utilities.
command.define({
name = "JSON: Format",
run = function()
local position = editor.getCursor()
local tree = markdown.parseMarkdown(editor.getText())
local fencedCode = nodeParentOfType(tree, position, "FencedCode")
if not fencedCode then
editor.flashNotification('Not in a fenced code block!')
return
end
-- Find the CodeInfo block.
local codeInfo = recursiveFindFirstChild(fencedCode, 'CodeInfo')
if not codeInfo then
editor.flashNotification('Type not set in fenced code block!')
return
end
-- nil for type means a text node, weirdly.
local codeLanguage = recursiveFindFirstChild(codeInfo, nil)
print(codeLanguage)
if not codeLanguage or codeLanguage.text ~= 'json' then
editor.flashNotification('Not in a JSON code block!')
return
end
local codeTextBlock = recursiveFindFirstChild(fencedCode, 'CodeText')
if not codeTextBlock then
editor.flashNotification('Could not find text block in code block!')
return
end
local codeTextNode = recursiveFindFirstChild(codeTextBlock, nil)
if not codeTextNode or not codeTextNode.text then
editor.flashNotification('Could not find actual code!')
return
end
formatJsonInTree(codeTextNode)
end,
})
-- Recurses down a ParseTree looking at children, trying to find
-- the child that matches the given type. Returns the child if found,
-- nil if not found.
local function recursiveFindFirstChild(tree, childType)
if not tree then return nil end
if tree.type == childType then
return tree
end
if not tree.children then
return nil
end
for child in each(tree.children) do
local foundChild = recursiveFindFirstChild(child, childType)
if foundChild then
return foundChild
end
end
return nil
end
local function formatJsonInTree(tree)
-- Retrieve the contents of the tree.
local jsonText = tree.text
local formatted = json.stringify(json.parse(jsonText))
editor.replaceRange(tree.from, tree.to, formatted)
end
-- Find outermost node of given type that contains the position
-- similar to plug-api/lib/tree.ts nodeAtPos
local function nodeParentOfType(tree, position, nodeType)
if position < tree.from or position > tree.to then
return nil
end
if tree.type == nodeType then
return tree
end
if tree.children then
for _, child in ipairs(tree.children) do
if position >= child.from and position <= child.to then
return nodeParentOfType(child, position, nodeType)
end
end
end
return nil
end