Today I took a gander at all the forum posts with the Templater tag. Most of them were already closed for replies, but I realized I had some comments that might appply to the following:
- Templater plugin: What’s the syntax for adding a parameter to a system command user function
- List of files inside folder
- Inserting more detailed weather forecasts into a daily note
As to the question about how to pass a parameter to a User System Command Function in Templater, I don’t think it is possible. However, I stopped using them in favor a User Script Function that allows me to build the command programmatically before passing it to the function to execute.
// In: cmd = a complete command to run in the command line shell. It is up
// to the user to make certain the command is properly formatted
// for their platform
// Out: an object with two properties:
// out = the trimmed content the command sent to standard out.
// err = the trimmed content the command sent to standard error.
async function sh(cmd)
{
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const result = await exec(cmd);
return {out: result.stdout.trim(), err: result.stderr.trim()};
}
module.exports = sh;
With the full power of the terminal (command line) available it opens up a lot of templating opportunities. For instance, one complex template I created built a table of contents using head
to extract the first few lines of notes and wc
to include their word counts. While that might be a bit complex to present here, I offer some concrete examples of the function in action below.
For the first example, the following template builds a simple list of the markdown files found at the root level of a vault:
<%*
const root = app.vault.adapter.getBasePath();
const escSpace = root.replace(/(\s)/g, '\\$1'); //escape the space characters
const list = await tp.user.sh(`ls ${escSpace}/*.md`);
const files = list.out.split('\n');
files.forEach(file => {tR += ` + ${file}\n`;});
-%>
sample output
+ /Users/ninjineer/Documents/Test/2022.calendar.md
+ /Users/ninjineer/Documents/Test/Book.md
+ /Users/ninjineer/Documents/Test/Counting words.md
+ /Users/ninjineer/Documents/Test/New-Day.md
+ /Users/ninjineer/Documents/Test/TVShow.md
+ /Users/ninjineer/Documents/Test/Terrible Idea 2.md
+ /Users/ninjineer/Documents/Test/Terrible Idea First.md
The above assumes you’re using MacOS or Linux. For Windows, the same template should look something like the following (note this code is untested as I do not have Obsidian running on a Windows computer):
<%*
const root = app.vault.adapter.getBasePath();
const list = await tp.user.sh(`dir "${root}\\*.md" /B`);
const files = list.out.split('\r\n');
files.forEach(file => {tR += ` + ${file}\r\n`;});
-%>
With a little more effort, once could also turn that file list into a list of links, like for a MOC:
<%*
const root = app.vault.adapter.getBasePath();
const escSpace = root.replace(/(\s)/g, '\\$1');
const list = await tp.user.sh(`ls ${escSpace}/*.md`);
const files = list.out.split('\n');
files.forEach(file => {
const parts = file.split('/');
const name = parts[parts.length - 1].slice(0,-3)
tR += ` + [[${name}]]\n`;
});
-%>
sample output
+ [[2022.calendar]]
+ [[Book]]
+ [[Counting words]]
+ [[New-Day]]
+ [[TVShow]]
+ [[Terrible Idea 2]]
+ [[Terrible Idea First]]
Another example comes from the post about inserting weather forcasts. The template for doing that in my location looks like:
<%*
const w = await tp.user.sh(`curl "https://wttr.in/Pohnpei?TuF0"`);
tR += '```\n' + w.out + '\n```\n';
-%>
sample output
Weather report: Pohnpei
Overcast
.--. +78(86) °F
.-( ). ← 2 mph
(___.__)__) 14 mi
0.1 in
I’ll leave you with one final example that occurred to me as I wrote this post. Since my vault is also a git repository, I periodically have to jump over to the terminal and commit my changes. With this sh
function, I can use a template to automate this task:
<%*
let msg = await tp.system.prompt("Git Commit Message","");
if (msg != null && msg.length > 1)
{
const root = app.vault.adapter.getBasePath();
const escSpace = root.replace(/(\s)/g, '\\$1');
const c = await tp.user.sh(`cd ${escSpace} && git add --all && git commit -m "${msg}"`)
console.log(c.out);
}
-%>
Note, I directed the output from the command to the console, but I could have just as easily funneled it into a note, if I wanted to keep a log of such commits for some reason.
I hope these examples trigger fresh idea in others. Thanks.