Skip to content

Instantly share code, notes, and snippets.

@mjf
Last active May 27, 2025 10:27
Show Gist options
  • Save mjf/76d3e29095cc2ff4f708d9c5ec0d36ad to your computer and use it in GitHub Desktop.
Save mjf/76d3e29095cc2ff4f708d9c5ec0d36ad to your computer and use it in GitHub Desktop.
SilverBullet Pending Tasks Widget

Pending Tasks Widget

SilverBullet supports tasks, like the following two:

  • provide working space-lua code,
  • explain everything (e.g., the meaning of life).

To make some use of them we should be able to at least list them. That can be achieved using SilverBullet query: ${query[[from index.tag 'task']]} which shows table with all tasks in any state from the whole space. Our goal for now is on every page to see pending tasks from the page at the bottom of the page.

Note

The query[[ ... ]] is not a function call! Rather, it is SilverBullet's syntactic extension to the normal Lua language syntax.

First we create Lua (space-lua) function to query and filter tasks present in the space. We can use, e.g., table called my for our collection of custom functions.

```space-lua
my = my or {}

my.pendingTasks = function(page)
  return query
  [[
    from
      task = index.tag 'task'
    where
      not task.done and
      (
        not page or
        page == task.page
      )
  ]]
end
```

You can try to call the function itself like this: ${my.pendingTasks()} which shows all pending tasks in the space, or for any particular page like this: ${my.pendingTasks('Some/Page/Name')} which shows tasks pending on that particular page only.

Note

You must reload the SilverBullet system and widgets to make it work, either from the command menu or by pressing Ctrl-Alt-R (on Linux). You must do the reload after every change you do in the Lua code.

```space-lua
widgets = widgets or {}

widgets.pendingTasks = function(page)
  local tasks = my.pendingTasks(page)
  local count = #tasks

  if not count then
    return
  end
  
  local markdown = '# ' .. count .. ' pending task' .. (count > 1 and 's' or '') .. '\n'

  for _, task in ipairs(tasks) do
    markdown = markdown .. '- ' .. task.text .. ' ([[' .. task.page .. '@' .. task.pos + 1 .. '|visit]])\n'
  end

  return widget.new {
    markdown = markdown
  }
end
```

Also this function can be used as is and everywhere. It renders a Markdown block: ${widgets.pendingTasks()} which shows all pending tasks from the space as Markdown list with clickable (visit) links pointing to the exact page and the exact place on that page the task is present. Again, a path (a name of a page) can be used as argument to the function.

Now, there are top and bottom hooks for rendering widgets in SilverBullet:

  • renderBottomWidgets and
  • renderTopWidgets.

To show at the bottom of the page a hook to the bottom widgets rendering must be registered.

If only the pending tasks that are present on the page we are currently editing should be listed the editor.getCurrentPage() function must be called to provide the name of the the current page.

```space-lua
event.listen {
  name = 'hooks:renderBottomWidgets',
  run = function()
    return widgets.pendingTasks(editor.getCurrentPage())
  end
}
```

After reloading SilverBullet you should see pending tasks at the bottom of the page.

Pending Tasks Widget

my = my or {}

my.pendingTasks = function(page)
  return query
  [[
    from
      task = index.tag 'task'
    where
      not task.done and
      (
        not page or
        page == task.page
      )
  ]]
end

${my.pendingTasks()}

widgets = widgets or {}

widgets.pendingTasks = function(page)
  local tasks = my.pendingTasks(page)
  local count = #tasks

  if not count then
    return
  end
  
  local markdown = '# ' .. count .. ' pending task' .. (count > 1 and 's' or '') .. '\n'

  for _, task in ipairs(tasks) do
    markdown = markdown .. '- ' .. task.text .. ' ([[' .. task.page .. '@' .. task.pos + 1 .. '|visit]])\n'
  end

  return widget.new {
    markdown = markdown
  }
end

${widgets.pendingTasks()}

event.listen {
  name = 'hooks:renderBottomWidgets',
  run = function()
    return widgets.pendingTasks(editor.getCurrentPage())
  end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment