Get recent todo lists with % complete (lua)

Made this space lua snippet recently to collect todo lists. It gets all the tasks in an index, finds what percent of them are complete in each note, sorts them by date modified, and writes the result as an array, which can be rendered as bullets through a ${} block.

Here’s a screenshot of what its output looks like:

raw markdown:

- [[Shopping List]] (100%)
- [[Summer TODO]] (82%)
- [[General tasks]] (1%)

Here’s the code for it:

-- generate a bulleted list of notes with tasks and what percent of them are complete in each note
local generate_bulleted_tasklist = function()
  -- all tasks
  local tasks_todo = query [[
    from index.tag 'task'
  ]]

  -- references to date modifed
  local ref_datemodified = {}
  for _, row in pairs(query [[ from index.tag 'page' ]]) do
    ref_datemodified[row.ref] = row.lastModified
  end

  -- add "lastModified" to the tasks_todo table
  for _, row in pairs(tasks_todo) do
    row.lastModified = ref_datemodified[row.page]
  end

  -- count how many tasks each note has
  local tasks_per_note = {}
  for _, row in pairs(tasks_todo) do
    local idx = row.page
    local current = tasks_per_note[idx] or { complete = 0, total = 0 }
    local complete = current.complete or 0
    local total = current.total or 0 
    tasks_per_note[idx] = {
      complete = complete + (row.done and 1 or 0),
      total = total + 1,
    }
  end

  -- mathematical round
  local round = function(f)
    local rem = f - math.floor(f)
    f = rem >= 0.5 and math.ceil(f) or math.floor(f)
    return f
  end

  -- format a list of strings based on tasks_per_note
  local tasks_per_note_list = {}
  for note, done in pairs(tasks_per_note) do
    local done_percent = round((done.complete/done.total)*100)
    tasks_per_note_list[#tasks_per_note_list + 1] = {
      note = note,
      lastModified = ref_datemodified[note],
      done_percent = done_percent,
    }
  end

  -- final query
  return query [[
    from tasks_per_note_list
    order by lastModified desc
    limit 15
    select '[' .. '[' .. note .. ']' .. '] (' .. tostring(done_percent) .. '%)'
  ]]
end

It would be a bit simpler to write this kind of thing if there was a clean way to get the lastModified attribute along with the result of the index.tag('task') query, since most of the code here is dedicated to combining the appropriate data from the index.tag('task') list with the index.tag('page') list to get the lastModified and done attributes associated with each page. If there’s a way I can refactor this to not need to do that, I’d like to know!

1 Like