Skip to content

[FEATURE] Obsidian style task completion #186

@webdavis

Description

@webdavis

Feature Description

An Obsidian style task completion that appends the completion date, like so:

  • This is a test ✅ 2025-12-28

Use Case

Just visibility on task lists. Great for local Claude Code issue tracking.

Proposed Solution

Something like this?

-- `map` is just my custom frontend with sane defaults for `vim.keymap.set`:
map({
  mode = "n",
  lhs = "<localleader>x",
  rhs = function()
    local bufnr = vim.api.nvim_get_current_buf()
    local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
    local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)

    -- 1. Start row is always the current line (checkbox line)
    local start_row = row

    -- 2. End row expands downward while lines are indented
    local end_row = row
    while end_row < #lines and lines[end_row + 1]:match("^%s") do
      end_row = end_row + 1
    end

    local first_line = lines[start_row]

    -- 3. Detect checkbox state on first line of task.
    local unchecked = first_line:match("^%s*%- %[ %]") ~= nil
    local checked = first_line:match("^%s*%- %[[xX]%]") ~= nil

    -- 4. Toggle the checkbox.
    local new_checked
    if unchecked then
      lines[start_row] = first_line:gsub("^(%s*%-+%s*)%[ %]", "%1[x]") -- check
      new_checked = true
    elseif checked then
      lines[start_row] = first_line:gsub("^(%s*%-+%s*)%[[xX]%]", "%1[ ]") -- uncheck
      new_checked = false
    else
      vim.notify("Not a valid Markdown task", vim.log.levels.WARN, { title = "Markview" })
      return
    end

    -- 5. Handle the completion comment on the last line.
    local last_line = lines[end_row]
    local comment_pattern = "%s*<!%-%- completed: %d%d%d%d%-%d%d%-%d%d %-%->"
    local comment = " <!-- completed: " .. os.date("%Y-%m-%d") .. " -->"

    if new_checked then
      if not last_line:match(comment_pattern) then
        lines[end_row] = last_line .. comment
      end
    else
      lines[end_row] = last_line:gsub(comment_pattern, "")
    end

    -- 6. Write back updated lines to buffer.
    -- stylua: ignore
    vim.api.nvim_buf_set_lines(
      bufnr,
      start_row - 1,
      end_row,
      false,
      vim.list_slice(lines, start_row, end_row)
    )
  end,
  desc = "Markdown: toggle checkbox (append completion date)",
})

Example output:

- [x] This is a test <!-- completed: 2025-12-28 -->

Alternatives Considered

Maybe the postfix format? My example doesn't render it on the web, but a config option could easily be implemented so that it shows up Obsidian style, as seen in the Feature Description.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions