Aligned with outline-PKM-apps indent behavior
To replicate batch indentation and de-indentation of selected nodes behaviors of some outline-oriented note-taking apps, I made a plugin that mirrors this interaction:
Ctrl-] = Header: Indent Selected
Ctrl-[ = Header: Outdent Selected
similiar to [space-lua] Toggle / Rotate Header Level h1-h6-On/Off 's second script rotate header level yet another batch version:
```space-lua
-- ======================================================
-- Helpers
-- ======================================================
-- Find 0-based line start index
local function getLineStart(text, pos)
if not text or not pos or pos <= 0 then return 0 end
local searchEnd = pos
if searchEnd > #text then searchEnd = #text end
-- Iterate backward to find the nearest newline
for i = searchEnd, 1, -1 do
if text:sub(i, i) == "\n" then
-- Return 0-based index of the character following \n
return i
end
end
return 0
end
-- Find 0-based line end index (including trailing \n)
local function getLineEnd(text, pos)
if not text or not pos or pos >= #text then return #text end
local searchStart = pos + 1
if searchStart < 1 then searchStart = 1 end
-- Iterate forward to find the nearest newline
for i = searchStart, #text do
if text:sub(i, i) == "\n" then
return i
end
end
return #text
end
-- Expand selection to cover full lines
local function getFullLineBoundaries(sel, text)
if not sel then return 0, #text end
if not text or text == "" then return 0, 0 end
local startPos = getLineStart(text, sel.from)
local effectiveEnd = sel.to
-- Prevent 'jump-down' bug: if cursor is at the start of a new line, retreat to previous line
if sel.to > sel.from and sel.to > 0 then
if sel.to <= #text then
if getLineStart(text, sel.to) == sel.to then
effectiveEnd = sel.to - 1
end
end
end
return startPos, getLineEnd(text, effectiveEnd)
end
-- ======================================================
-- Core Logic
-- ======================================================
-- Batch adjust header levels: delta 1 (Indent), -1 (Outdent)
local function batchUpdateHeaders(delta)
local sel = editor.getSelection()
if not sel then return end
local text = editor.getText()
if not text or text == "" then return end
-- 1. Get full line range
local rangeStart, rangeEnd = getFullLineBoundaries(sel, text)
-- 2. Validate indices
rangeStart = tonumber(rangeStart) or 0
rangeEnd = tonumber(rangeEnd) or #text
if rangeStart < 0 then rangeStart = 0 end
if rangeEnd > #text then rangeEnd = #text end
if rangeStart > rangeEnd then rangeStart, rangeEnd = rangeEnd, rangeStart end
-- 3. Extract target text block (1-based Lua sub)
local textBlock = text:sub(rangeStart + 1, rangeEnd)
if not textBlock or textBlock == "" then return end
local newLines = {}
-- 4. Process line-by-line
for line in textBlock:gmatch("([^\n]*\n?)") do
if line ~= "" then
local hashes, rest = line:match("^(#+)%s(.*)")
if hashes then
local currentLevel = #hashes
if delta > 0 then
-- Indent: Increase header level (max H6)
if currentLevel < 6 then
line = "#" .. line
end
elseif delta < 0 then
-- Outdent: Decrease level or convert H1 to plain text
if currentLevel > 1 then
line = line:sub(2)
elseif currentLevel == 1 then
line = line:gsub("^#%s", "", 1)
end
end
end
table.insert(newLines, line)
end
end
-- 5. Execute replacement and reset selection to prevent drift
if #newLines > 0 then
local newText = table.concat(newLines)
if newText ~= textBlock then
editor.replaceRange(rangeStart, rangeEnd, newText)
end
editor.setSelection(rangeStart, rangeStart + #newText)
end
end
-- ======================================================
-- Command Registration
-- ======================================================
command.define {
name = "Header: Indent Selected",
key = "Ctrl-]",
run = function()
batchUpdateHeaders(1)
end
}
command.define {
name = "Header: Outdent Selected",
key = "Ctrl-[",
run = function()
batchUpdateHeaders(-1)
end
}
Insterested in the Jumpable floating TOC ?
meet the up-to-date HHH - HierarchyHighlightHeadings Theme - #5 by ChenZhu-Xie
i.e., the HHH Library: https://github.com/ChenZhu-Xie/xczphysics_SilverBullet/blob/main/Library/xczphysics/CONFIG/batch/Header_Indent.md
hard to explain what it is… (until you take a try : )
About my Repo
My repository focuses on pragmatic shortcut scripts that reduce keystroke overhead to accomplish equivalent tasks more efficiently, enhancing the overall workflow:
see: https://github.com/ChenZhu-Xie/xczphysics_SilverBullet/blob/main/Repositories/xczphysics.md