Easy text selection into a code block using a hotkey (Templater)

Mostly for CSS, but I found myself wanting to quickly create a fenced code block from selected text without typing ``` and then the code language over and over again. I’ve been using a few different versions for months now without issue. Hopefully, a few of you will find it useful!

Setup:

  • Install the Templater community plugin.

  • Paste the below code into a new note, give it a template sounding name that works for you, and move it to your Templater templates folder.

  • Set a “Template Hotkey” for this template in Templater’s settings.

  • Assign/configure the hotkey. I use Cmd + Optn + C, but it can be anything as long as the hotkey isn’t already assigned.

The template:

<%*
//get selection
noteContent = tp.file.selection();
//get array of lines
lines = noteContent.split('\n')
//
let newContent = "";
lines.forEach(l => {
    newContent += '' + l + "\n";
})
//
newContent = newContent.replace(/\n$/, "");
//assign the code block language - change {css} to {html}, {php}, etc.
header = "```css"+ "\n"
//place cursor after last selected character and add final backticks 
return header + newContent + "\<% tp.file.cursor() %\>" + "\n" + "```";
%>

Usage:

If there’s no text selected and you run the template / use the hotkey, you’ll get this:

```css
<cursor here>
```

CleanShot 2024-04-09 at 10.03.48

If there’s text selected and you run the template / use the hotkey, everything will be neatly wrapped up in a code block:

CleanShot 2024-04-09 at 10.08.38


Special thanks to Zachatoo for the assist in getting the final cursor location sorted out.

It shouldn’t eat your CSS, any other code, or text, but it is provided as is. Enjoy! :cherry_blossom:

2 Likes

I refined this a little further.

Not sure why you’re iterating over each line since tp.file.selection() preserves line breaks?

Anyways Obsidian uses prismJS under the hood, so i scraped the supported languages off their homepage to populate a suggester:

<%*
let codeHints;
try {
    syntax = JSON.parse(await app.vault.read(tp.file.find_tfile("prismLanguages.json")));
} catch (error) {
    console.error('JSON Parse:', error);
}
syntax.hints.push(" ", "dataview", "dataviewjs", "tasks");
syntax.hints.sort();

let hint = await tp.system.suggester(syntax.hints, syntax.hints, false, "Code Block Hint");
if(hint === null) {
    return;
} else {
    return  "```" + `${hint}\n` + `${tp.file.selection()}\<% tp.file.cursor() %\>\n` + "```\n\n";
}
_%>
{
    "hints": [
    "abap", "abnf", "actionscript", "ada", "adoc", "agda", "al", "antlr4", "apacheconf", "apex", 
    "apl", "applescript", "aql", "arduino", "arff", "arm-asm", "armasm", "art", "arturo", "asciidoc", 
    "asm6502", "asmatmel", "aspnet", "atom", "autohotkey", "autoit", "avdl", "avisynth", "avro-idl", "avs", 
    "awk", "bash", "basic", "batch", "bbcode", "bbj", "bicep", "birb", "bison", "bnf", 
    "bqn", "brainfuck", "brightscript", "bro", "bsl", "c", "cfc", "cfscript", "chaiscript", "cil", 
    "cilk", "cilk-c", "cilk-cpp", "cilkc", "cilkcpp", "clike", "clojure", "cmake", "cobol", "coffee", 
    "coffeescript", "conc", "concurnas", "context", "cooklang", "coq", "cpp", "crystal", "cs", "csharp", 
    "cshtml", "csp", "css", "css-extras", "csv", "cue", "cypher", "d", "dart", "dataweave", 
    "dax", "dhall", "diff", "django", "dns-zone", "dns-zone-file", "docker", "dockerfile", "dot", "dotnet", 
    "ebnf", "editorconfig", "eiffel", "ejs", "elisp", "elixir", "elm", "emacs", "emacs-lisp", "erb", 
    "erlang", "eta", "etlua", "excel-formula", "factor", "false", "firestore-security-rules", "flow", "fortran", "fsharp", 
    "ftl", "g4", "gamemakerlanguage", "gap", "gawk", "gcode", "gdscript", "gedcom", "gettext", "gherkin", 
    "git", "gitignore", "glsl", "gml", "gn", "gni", "go", "go-mod", "go-module", "gradle", 
    "graphql", "groovy", "gv", "haml", "handlebars", "haskell", "haxe", "hbs", "hcl", "hgignore", 
    "hlsl", "hoon", "hpkp", "hs", "hsts", "html", "http", "ichigojam", "icon", "icu-message-format", 
    "idr", "idris", "iecst", "ignore", "inform7", "ini", "ino", "io", "j", "java", 
    "javadoc", "javadoclike", "javascript", "javastacktrace", "jexl", "jinja2", "jolie", "jq", "js", "js-extras", 
    "js-templates", "jsdoc", "json", "json5", "jsonp", "jsstacktrace", "jsx", "julia", "keepalived", "keyman", 
    "kotlin", "kt", "kts", "kum", "kumir", "kusto", "latex", "latte", "ld", "less", 
    "lilypond", "linker-script", "liquid", "lisp", "livescript", "llvm", "log", "lolcode", "lua", "ly", 
    "magma", "makefile", "markdown", "markup", "markup-templating", "mata", "mathematica", "mathml", "matlab", "maxscript", 
    "md", "mel", "mermaid", "metafont", "mizar", "mongodb", "monkey", "moon", "moonscript", "mscript", 
    "mustache", "n1ql", "n4js", "n4jsd", "nand2tetris-hdl", "nani", "naniscript", "nasm", "nb", "neon", 
    "nevod", "nginx", "nim", "nix", "npmignore", "nsis", "objc", "objectivec", "objectpascal", "ocaml", 
    "odin", "opencl", "openqasm", "oscript", "oz", "parigp", "parser", "pascal", "pascaligo", "pbfasm", 
    "pcaxis", "pcode", "peoplecode", "perl", "php", "php-extras", "phpdoc", "plant-uml", "plantuml", "plsql", 
    "po", "powerquery", "powershell", "pq", "processing", "prolog", "promql", "properties", "protobuf", "psl", 
    "pug", "puppet", "pure", "purebasic", "purescript", "purs", "px", "py", "python", "q", 
    "qasm", "qml", "qore", "qs", "qsharp", "r", "racket", "razor", "rb", "rbnf", 
    "reason", "regex", "rego", "renpy", "res", "rescript", "rest", "rip", "rkt", "roboconf", 
    "robot", "robotframework", "rpy", "rq", "rss", "ruby", "rust", "sas", "sass", "scala", 
    "scheme", "sclang", "scss", "sh", "sh-session", "shell", "shell-session", "shellsession", "shortcode", "sln", 
    "smali", "smalltalk", "smarty", "sml", "smlnj", "sol", "solidity", "solution-file", "soy", "sparql", 
    "splunk-spl", "sqf", "sql", "squirrel", "ssml", "stan", "stata", "stylus", "supercollider", "svg", 
    "swift", "systemd", "t4", "t4-cs", "t4-templating", "t4-vb", "tap", "tcl", "tex", "textile", 
    "toml", "tremor", "trickle", "trig", "troy", "ts", "tsconfig", "tsx", "tt2", "turtle", 
    "twig", "typescript", "typoscript", "uc", "unrealscript", "uorazor", "uri", "url", "uscript", "v", 
    "vala", "vb", "vba", "vbnet", "velocity", "verilog", "vhdl", "vim", "visual-basic", "warpscript", 
    "wasm", "web-idl", "webidl", "webmanifest", "wgsl", "wiki", "wl", "wolfram", "wren", "xeora", 
    "xeoracube", "xls", "xlsx", "xml", "xml-doc", "xojo", "xquery", "yaml", "yang", "yml", 
    "zig"
    ]
}

Isn’t this essentially the same as using that one simple line? Why make it more complex?

```css
<% tp.file.cursor() %><% tp.file.selection() %>
```
1 Like