Access filename of new file in templates and space scripts during creation

Hi there,

I’ve tried many note taking apps but the one that have stuck for me is silverbullet. It’s as great as it is simple. But now I find myself being limited by, most likely, my own knowledge. I’ve been looking for an answer to this for days and experimented with different ways of doing this, all with no success. I’m not very experienced in JS and I have not found any extensive documentation on silverbullet or its components so my attempts so far has been based on examples from this forum, github, and my previous coding knowledge (mostly Python).

TLDR;

I need to pass a custom date (i.e. 2024-06-08), which is created by me when the template is run, into a {{variable/function/method}} and/or a space-script for further processing i.e. getting a week range based on that date. Using name doesn’t work, only “hardcoded” values seems to work or the template won’t run. I need to capture the filename somehow after the fact and I’m stumped on how to achieve this. Grateful for any suggestions/help.

Short summary:
I have a template to create a daily journal and these notes are named based on date (Journal/Year/Month/Date => Journal/2024/06/2024-06-16.md). In these I create daily notes and tasks, and I also want to show all overdue tasks and all tasks with a deadline of the week of the date of the journal i.e. for 2024-06-16 that would be all tasks between 2024-06-10 and 2024-06-16.

For the current date, {{today}}, that is not an issue since it’s easy to do with the help of the Additional Date Functions space script and any other Temporal scripting during the creation of the note via the template, but where it becomes a problem is for dates that are custom/not today’s date, that is, set by me when running the template. I sometimes need to create daily/weekly journals for past dates and in those cases {{today}} won’t work.

What I’m currently doing:
If I want to create a daily journal for 2024-06-08 (last week) I do so by creating the file Journal/2024/06/2024-06-08.md using my Daily Journal Template. In this template I create a header based on the filename with the help of some regex to extract it;

# Frontmatter
tags: template
frontmatter:
  monthCreated: "{{monthNumber}}"
  weekCreated: "{{weekNumber}}"
  weekStart: "{{weekStart}}"
  weekEnd: "{{weekEnd}}"
  dateCreated: "{{today}}"
  filePath: "{{name}}"
  fileName: "{{getFileName(name)}}"
  type: journal
  tags: journal, daily
hooks.newPage:
  suggestedName: "Journal/{{year}}/{{month}}/{{today}}"
  confirmName: true
  openIfExists: true
  forPrefix: "Journal/Year/Month/Day/"

# Template header:
{{getFileName(name)}}

# Space-script:
silverbullet.registerFunction({name: "getFileName"}, (fullPath) => {
  const regExStr = /^(.*[\\\/])/
  const fileName = fullPath.replace(regExStr, "");
  return fileName;
})

What I need help with:
The problem I have is trying to create a date range for a weekly view when using a custom date for the file I’m creating with the template, which is also the filename i.e. 2024-06-08. In simple terms, whatever date I name the file I want to list the tasks for the week range of that date/filename.

In the Additional Date Functions script there is a function called weekNumberFor and I’ve created a similar one called weekStartFor.

silverbullet.registerFunction({name: "weekEndFor"}, (dateString) => {
  const dateObj = Temporal.PlainDate.from(dateString);
  const lastDayOfWeek = dateObj.add({days: 7 - dateObj.dayOfWeek});
  return lastDayOfWeek.toString();
})
silverbullet.registerFunction({name: "weekStartFor"}, (dateString) => {
  const dateObj = Temporal.PlainDate.from(dateString);
  const firstDayOfWeek = dateObj.subtract({days: dateObj.dayOfWeek - 1});
  return firstDayOfWeek.toString();
})

If I try to use name when calling any of these functions e.g. {{weekStartFor(name)}}, {{weekStartFor(name)}}, {{getFileName(name)}} then the template won’t run. When using a static value i.e. {{weekStartFor(“2024-06-08”)}} it runs fine. The problem is the filename is unknown until when I run the template and then name the file (confirmName: true) with the date of my choosing.

With that custom date/filename I want to run something like this (simple examples which won’t work in their current state) where the {{variables}}|@variables are calculated based on the custom date/filename created:

Example 1:

task
where deadline > "{{weekStartForVariable}}" and deadline < "{{weekEndForVariable}}" and done = false and page =~ /^Journal/
order by page, deadline
render [[Library/Core/Query/Task]]

Example 2:

{{#let @curDate = getFileName(name)}}
{{#let @weekStartForVariable = weekStartFor(@curDate)}}
{{#let @weekEndForVariable = weekEndFor(@curDate)}}
{{#let @tasks = {task where deadline >= @weekStartForVariable and deadline <= @weekEndForVariable and done = false and page =~ /^Journal/ order by ref asc}}}
{{#each @tsk in @tasks}}
{{#if @tsk}}
[[{{@tsk.ref}}]]
- [{{@tsk.state}}] {{@tsk.name}} - {{@tsk.deadline}}
{{/if}}
{{/each}}
{{/let}}
{{/let}}
{{/let}}
{{/let}}

Thanks!

Hi, I think I had exactly the same problem when trying to add previous/next links to my daily journal.

I tried to access this filename in a few ways and didn’t succeed. But I used a template to evaluate it only when the file is shown, and then if I don’t want it to be templated anymore (for example to get red links), I use the bake button in the corner.

The escapeDirective call is needed to evaluate it when shown, not when created.


This is at the top of my Library/Journal/New Page/Daily Note (the links are Polish for “yesterday tomorrow”)

```template
[[{{escapeDirective('pageAddDays(@page.name, -1)')}}|wczoraj]] [[{{escapeDirective('pageAddDays(@page.name, 1)')}}|jutro]]
```

screenshot with bake button

Definition of pageAddDays for completion
```space-script
silverbullet.registerFunction("pageAddDays:", (page, days) => {
  const parts = page.split("/");
  let date = parts[parts.length - 1];
  const plainDate = Temporal.PlainDate.from(date);
  const offsetDate = plainDate.add(Temporal.Duration.from({ days: Number(days) }));
  const result = parts.slice(0, -1);
  result.push(offsetDate.toString());
  return result.join("/");
});
```

Sorry I didn’t adapt it, I only have a moment to paste my current code. I hope that it still shows the approach to help with your solution :slight_smile:

2 Likes

I managed to find a solution to my problem!

Thanks Marek for your suggestion! I will have a look at it and see if it works for me as it looks like a simpler way of solving the issue than the one I came up with.

Solution:
I continued to debug the issue while also reading up on my JS skills and I eventually found that the cause of my issue was that the space-scripts were being read during the template creation process during which the name variable had not yet been set. Once the name had been set and the file had been created all space-scripts were run once again. For most functions this did not cause an issue as no errors were thrown but for the ones I had created the Temporal calls threw an error that stopped everything.

My simple solution was to implement try/catch in the code which allowed me to catch the first-run error, create the file (and name), and then have the scripts execute properly during the second-run.

Here’s the code that works (which I will now continue to work on to make it look better in the template):

Space-script: Get Week Range

// Get the last date of the week based on the date in the filename provided
silverbullet.registerFunction({name: "getWeekEnd"}, (fullPath) => {
  // Create regex to remove everything before the last /
  const regExStr = /^(.*[\\\/])/; 
  // Remove the path before the filename
  const fileName = fullPath.replace(regExStr, ""); 
  // try to run the code and catch any error thrown while continuing all other scripts
  try { 
    // Get the date object from the filename (format YYYY-MM-DD)
    const dateObj = Temporal.PlainDate.from(fileName);
    // Get the last day of the week based on the date/filename
    const lastDayOfWeek = dateObj.add({days: 7 - dateObj.dayOfWeek});
    // Turn it into a string and return it
    return lastDayOfWeek.toString();
  } 
  catch (error) {
    const e = new ErrorEvent('error', {message:'Error:', error:error})
    window.dispatchEvent(e)
  }
})

// Get the first date of the week based on the date in the filename provided
silverbullet.registerFunction({name: "getWeekStart"}, (fullPath) => {
  const regExStr = /^(.*[\\\/])/;
  const fileName = fullPath.replace(regExStr, "");
  try {
    const dateObj = Temporal.PlainDate.from(fileName);
    console.log('dateObj.dayOfWeek', dateObj.dayOfWeek)
    const firstDayOfWeek = dateObj.subtract({days: dateObj.dayOfWeek - 1});
    return firstDayOfWeek.toString();
  } 
  catch (error) {
    const e = new ErrorEvent('error', {message:'Error:', error:error})
    window.dispatchEvent(e)
  }
})

The code in my template which shows all open tasks with a deadline set during the week based on the filename/date (static):

{{#let @wkStart = getWeekStart(name)}}
{{#let @wkEnd = getWeekEnd(name)}}
{{#let @tasks = {task where deadline >= @wkStart and deadline <= @wkEnd and done = false and page =~ /^Journal/ order by ref asc}}}
{{#each @tsk in @tasks}}
{{#if @tsk}}
[[{{@tsk.ref}}]]
- [{{@tsk.state}}] {{@tsk.name}} - {{@tsk.deadline}}
{{/if}}
{{/each}}
{{/let}}
{{/let}}
{{/let}}

Alternative way of showing the data in a query instead (not static):

task
where deadline >= "{{getWeekStart(name)}}" and deadline <= "{{getWeekEnd(name)}}" and done = false and page =~ /^Journal/
order by page, deadline
render [[Library/Core/Query/Task]]
1 Like