I have a new-and-improved script now
Features
- can be used to set headings to specific level, or increase/decrease
- multi-line: increase/decrease all headings in multi-line selection
- “promote” defaults to heading level 3 if no heading in selection
- preserve cursor position / selection
Script
/* Set the heading to the specified level.
* If the level is negative, will decrease heading size by that much.
* If the level is 0 or undefined, will increase the heading by one, or turn a non-heading into a level-3 heading
*/
function setHeading(level) {
const editor = app.workspace.activeLeaf.view.editor;
const cAnchor = editor.getCursor('anchor');
const cHead = editor.getCursor('head');
const top = {line: Math.min(cAnchor.line, cHead.line), ch: 0};
const bottom = {line: Math.max(cAnchor.line, cHead.line), ch: Infinity};
const lineRange = editor.getRange(top, bottom);
let replacement = lineRange;
if (!level) {
// promote all headings in lineRange. If no heading in lineRange, promote all lines to h3
if (!lineRange.match(/^#+ /m)) {
replacement = lineRange.replace(/^/gm, "### ");
}
else { // otherwise promote by 1
replacement = lineRange.replace(/^#(#+) /gm, "$1 ");
}
}
else if (level < -1)
console.error("Heading level of less than -1 is not supported, demoting heading(s) by one only. Aborting.");
else if (level == -1) {
replacement = lineRange.replace(/^#+ /gm, "#$&");
}
else {
// set lineRange to header level
console.log(`set header to level: ${level}.`);
if (!lineRange.match(/^#+ /m)) {
console.log('no headings found, replacing all lines')
replacement = lineRange.replace(/^/gm, "#".repeat(level)+" ");
}
else {
console.log('replace certain headings')
replacement = lineRange.replace(/^#+ (.*)/gm, "#".repeat(level) + " $1");
}
}
editor.replaceRange(replacement, top, bottom);
// adjust new selection
let lines = lineRange.split('\n');
let newLines = replacement.split('\n');
[cAnchor, cHead].forEach(p => {
let i = p.line - top.line;
if (p.ch)
p.ch += newLines[i].length - lines[i].length;
});
editor.setSelection(cAnchor, cHead);
return;
}
module.exports = setHeading;
Instructions
- Install Templater
- Create a file called “setHeading.js” in your vault (I suggest putting it in a folder called “Scripts”)
- copy and paste the content (Script) from above
- you will have to use a text editor other than Obsidian to create the js file
- Create two markdown files in your templates folder with the following content:
and<%* tp.user.setHeading(); return; %>
<%* tp.user.setHeading(-1); return; %>
- you can also use numbers 1 – 6 to set headings to a specific level
- Name the files something like “Increase Headings” and “Decrease Headings”
- In Templater Settings, make sure you can see
tp.user.setHeading
in the User Script Functions section. - Add a Template Hotkey for each of the templates you just created and set to your desired shortcuts in Obsidian Settings > Hotkeys
- Enjoy