# \[space-lua\] Toggle / Rotate Header Level h1-h6-On/Off

**URL:** https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320
**Category:** Tricks & Techniques
**Created:** [October 2, 2025, 5:29pm UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320 "2025-10-02T17:29:08Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Mr.Red](https://community.silverbullet.md/user_avatar/community.silverbullet.md/mr.red/32/821_2.png) [@Mr.Red](https://community.silverbullet.md/u/Mr.Red)
#### Post date: [October 2, 2025, 5:29pm UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/1 "2025-10-02T17:29:08Z")

</div>

I was having a “productive conversation” with ChatGPT today and after a couple of back and forth, together we cooked up these two little handy Shortcut-Commands:

## First one is to toggle h1-h6 level headers with one convenient combo-keypress (Ctrl-1 to Ctrl-6):

```auto
-- function to toggle a specific header level
local function toggleHeader(level)
  local line = editor.getCurrentLine()

  -- handle empty line
  if not line or not line.text then
    editor.insertAtCursor(string.rep("#", level) .. " ")
    return
  end

  local s, from, to = line.text, line.from, line.to

  local prefix, rest = s:match("^(#+)%s+(.*)")
  local currentLevel = prefix and #prefix or 0

  local newLine
  if currentLevel == level then
    newLine = rest or s -- remove header
  else
    newLine = string.rep("#", level) .. " " .. (rest or s) -- set header to desired level
  end

  editor.replaceRange(from, to, newLine)
  editor.moveCursor(from + #newLine, false)
end

-- register commands Ctrl-1 → Ctrl-6
for lvl = 1, 6 do
  command.define {
    name = "Header: Toggle Level - h" .. lvl,
    key = "Ctrl-" .. lvl,
    run = function() toggleHeader(lvl) end
  }
end

```

## The second one to rotate header level between [h1-h2-h3-h4-h6-off] using Ctrl-Shift-Tab:

```auto
command.define {
  name = "Header: Rotate level",
  key = "Ctrl-Shift-Tab",
  run = function()
    local line = editor.getCurrentLine()
    
    -- If the line is completely empty (or nil), insert "# " at cursor
    if not line or not line.text then
      local cursor = editor.getCursor() or 0
      editor.insertAtCursor("# ")
      return
    end

    -- Normal case
    local s, from, to = line.text, line.from, line.to

    local hashes, rest = s:match("^(#+)%s+(.*)")
    local level = hashes and #hashes or 0

    local newLine = level < 6 and string.rep("#", level + 1) .. " " .. (rest or s) or (rest or s)

    editor.replaceRange(from, to, newLine)
    editor.moveCursor(from + #newLine, false)
  end
}

```

Feel free to modify the Shortcut keys to your liking, also i am not a coder or a developer so you can also comment and/or improve the script itself, and also leave some feedback if you think it´s useful for you or not 😉

---

<div class="post-metadata">

### Author: ![zef](https://community.silverbullet.md/user_avatar/community.silverbullet.md/zef/32/7_2.png) [@zef](https://community.silverbullet.md/u/zef)
#### Post date: [October 2, 2025, 6:56pm UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/2 "2025-10-02T18:56:37Z")

</div>

Interesting. Are you aware that the /h1 - /h4 slash commands _update_ your current line to the desired level? This is what I always use.

---

<div class="post-metadata">

### Author: ![Mr.Red](https://community.silverbullet.md/user_avatar/community.silverbullet.md/mr.red/32/821_2.png) [@Mr.Red](https://community.silverbullet.md/u/Mr.Red)
#### Post date: [October 2, 2025, 7:07pm UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/3 "2025-10-02T19:07:05Z")

</div>

yes but that’s a couple of keypresses more:

“Space” + “/” + “h” + “1” + “Enter” - 5x keypresses (both hands used)

vs.

“Ctrl” + “1” - 1x ComboKey press (one hand)

And also the /slash command doesn’t turn the current header level off unless you manually delete the “######” in front of the header(and that could be a lot of keypresses 😛 )  
I was going for a quicker shortcut and not necessarily a “missing feature”.

BTW, is there a way to attach a shortcut key to a /slash command like in v1 ? That is what I was trying to mimic with my two commands. If there was a way to assign Shortcut Keys to /slash commands too, that would be awesome. (I didn’t find anything in the docs)

---

<div class="post-metadata">

### Author: ![Mr.Red](https://community.silverbullet.md/user_avatar/community.silverbullet.md/mr.red/32/821_2.png) [@Mr.Red](https://community.silverbullet.md/u/Mr.Red)
#### Post date: [October 3, 2025, 1:32pm UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/4 "2025-10-03T13:32:18Z")

</div>

Here is an updated version of the Header: Toggle Level commands.  
This is derived from the “built-in” /h1-/h5 slash commands and added the part to handle the toggling off. More straightforward and still retains all the functions.

```auto
-- function to toggle a specific header level

local function toggleHeader(level)
  local line = editor.getCurrentLine()
  local text = line.textWithCursor

  -- Detect current header level
  local currentLevel = string.match(text, "^(#+)%s*")
  currentLevel = currentLevel and #currentLevel or 0

  local cleanText = string.gsub(text, "^#+%s*", "")

  -- Toggle: remove if same, otherwise set new level
  if currentLevel == level then
    editor.replaceRange(line.from, line.to, cleanText, true)
  else
    editor.replaceRange(line.from, line.to, string.rep("#", level) .. " " .. cleanText, true)
  end
end

-- register commands Ctrl-1 → Ctrl-6
for lvl = 1, 6 do
  command.define {
    name = "Header: Toggle Level " .. lvl,
    key = "Ctrl-" .. lvl,
    run = function() toggleHeader(lvl) end
  }
end

```

---

<div class="post-metadata">

### Author: ![malys](https://community.silverbullet.md/user_avatar/community.silverbullet.md/malys/32/840_2.png) [@malys](https://community.silverbullet.md/u/malys)
#### Post date: [October 7, 2025, 11:58am UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/5 "2025-10-07T11:58:12Z")

</div>

Very productive. Thanks.

---

<div class="post-metadata">

### Author: ![ChenZhu-Xie](https://community.silverbullet.md/user_avatar/community.silverbullet.md/chenzhu-xie/32/1476_2.png) [@ChenZhu-Xie](https://community.silverbullet.md/u/ChenZhu-Xie)
#### Post date: [November 18, 2025, 9:49am UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/6 "2025-11-18T09:49:48Z")

</div>

did some clean up for @Mr.Red

now behaves correctly with cursor inside the `###... ` structure.

```auto
-- function to toggle a specific header level
local function toggleHead(level)
  local line = editor.getCurrentLine()
  
  local text = line.text
  local currentLevel = string.match(text, "^(#+)%s*")
  currentLevel = currentLevel and #currentLevel or 0
  
  local textC = line.textWithCursor
  local posC = string.find(textC, "|^|", 1, true)
  
  local lineHead
  if posC > currentLevel + 1 then
    local bodyTextC = string.gsub(textC, "^#+%s*", "")
    if currentLevel == level then
      lineHead = bodyTextC
    else
      lineHead = string.rep("#", level) .. " " .. bodyTextC
    end
  else
    local bodyText = string.gsub(text, "^#+%s*", "")
    if currentLevel == level then
      lineHead = "|^|" .. bodyText
    else
      lineHead = string.rep("#", level) .. " |^|" .. bodyText
    end
  end
  editor.replaceRange(line.from, line.to, lineHead, true)
end

-- register commands Ctrl-1 → Ctrl-6
for lvl = 1, 6 do
  command.define {
    name = "Header: Toggle Level " .. lvl,
    key = "Ctrl-" .. lvl,
    run = function() 
      toggleHead(lvl) 
    end
  }
end

```

---

<div class="post-metadata">

### Author: ![Mr.Red](https://community.silverbullet.md/user_avatar/community.silverbullet.md/mr.red/32/821_2.png) [@Mr.Red](https://community.silverbullet.md/u/Mr.Red)
#### Post date: [November 19, 2025, 7:59am UTC](https://community.silverbullet.md/t/space-lua-toggle-rotate-header-level-h1-h6-on-off/3320/7 "2025-11-19T07:59:42Z")

</div>

thanks, just updated my library with your fixes. 👍
