Did you check the docs?
Is your feature request related to a problem? Please describe.
The current select_todo only fetches todos from the current buffer, but I think it can be made more robust by searching todos throughout the project root.
Describe the solution you'd like
A picker that can fetch to-dos throughout the project root.
Features:
- User can set custom roots like
.obsidian etc.
- User can exclude directories or files from being searched by the picker. Useful when you have template files with checklist item in them.
- User can invoke picker through keymap for complete and incomplete tasks. Can be extended for custom
toggle_states.
Optional:
- Ability to toggle tasks directly from the picker (may not be feasible depending on the picker's capabilities)
Describe alternatives you've considered
Using Snacks.picker.grep() to achieve something similar, but I think it can be better integrated with the plugin.
Searching incomplete todo:
{
'<leader>Ti',
function()
local root = Util.root.get()
local exclude_dirs = {
'Templates',
'node_modules',
'.git',
'dist',
'build',
}
local exclude_patterns = vim.tbl_map(function(dir) return '**/' .. dir .. '/**' end, exclude_dirs)
Snacks.picker.grep {
prompt = ' ',
search = '^\\s*- \\[ \\]',
regex = true,
-- no “live grep” needed here since we have a fixed pattern
live = false,
-- restrict search to the current working directory
dirs = { root },
-- Only show for markdown files
glob = '*.md',
exclude = exclude_patterns,
-- include files ignored by .gitignore
args = { '--no-ignore' },
-- Start in normal mode
on_show = function() vim.cmd.stopinsert() end,
finder = 'grep',
format = 'file',
show_empty = true,
supports_live = false,
layout = 'ivy_split',
}
end,
desc = 'Search for incomplete tasks',
},
Searching completed todo:
{
'<leader>Tc',
function()
local root = Util.root.get()
local exclude_dirs = {
'Templates',
'node_modules',
'.git',
'dist',
'build',
}
local exclude_patterns = vim.tbl_map(function(dir) return '**/' .. dir .. '/**' end, exclude_dirs)
Snacks.picker.grep {
prompt = ' ',
-- search = "^\\s*- \\[x\\] `done:",
search = '^\\s*- \\[[xX]\\](?: `done:)?',
regex = true,
-- no “live grep” needed here since we have a fixed pattern
live = false,
-- restrict search to the current working directory
dirs = { root },
-- exclude directories
exclude = exclude_patterns,
-- include files ignored by .gitignore
args = { '--no-ignore' },
-- Start in normal mode
on_show = function() vim.cmd.stopinsert() end,
finder = 'grep',
format = 'file',
show_empty = true,
supports_live = false,
layout = 'ivy',
}
end,
desc = 'Search for complete tasks',
},
},
lua/util/root.lua:
local M = {}
function M.detect(opts)
opts = opts or {}
opts.spec = opts.spec or type(vim.g.root_spec) == "table" and vim.g.root_spec or M.spec
opts.buf = (opts.buf == nil or opts.buf == 0) and vim.api.nvim_get_current_buf() or opts.buf
local ret = {} ---@type UtilRoot[]
for _, spec in ipairs(opts.spec) do
local paths = M.resolve(spec)(opts.buf)
paths = paths or {}
paths = type(paths) == "table" and paths or { paths }
local roots = {} ---@type string[]
for _, p in ipairs(paths) do
local pp = M.realpath(p)
if pp and not vim.tbl_contains(roots, pp) then
roots[#roots + 1] = pp
end
end
table.sort(roots, function(a, b)
return #a > #b
end)
if #roots > 0 then
ret[#ret + 1] = { spec = spec, paths = roots }
if opts.all == false then
break
end
end
end
return ret
end
M.cache = {}
function M.is_win() return vim.uv.os_uname().sysname:find 'Windows' ~= nil end
function M.get(opts)
opts = opts or {}
local buf = opts.buf or vim.api.nvim_get_current_buf()
local ret = M.cache[buf]
if not ret then
local roots = M.detect({ all = false, buf = buf })
ret = roots[1] and roots[1].paths[1] or vim.uv.cwd()
M.cache[buf] = ret
end
if opts and opts.normalize then
return ret
end
return Util.is_win() and ret:gsub("/", "\\") or ret
end
return M
Additional context
No response
Did you check the docs?
Is your feature request related to a problem? Please describe.
The current
select_todoonly fetches todos from the current buffer, but I think it can be made more robust by searching todos throughout the project root.Describe the solution you'd like
A picker that can fetch to-dos throughout the project root.
Features:
.obsidianetc.toggle_states.Optional:
Describe alternatives you've considered
Using
Snacks.picker.grep()to achieve something similar, but I think it can be better integrated with the plugin.Searching incomplete todo:
{ '<leader>Ti', function() local root = Util.root.get() local exclude_dirs = { 'Templates', 'node_modules', '.git', 'dist', 'build', } local exclude_patterns = vim.tbl_map(function(dir) return '**/' .. dir .. '/**' end, exclude_dirs) Snacks.picker.grep { prompt = ' ', search = '^\\s*- \\[ \\]', regex = true, -- no “live grep” needed here since we have a fixed pattern live = false, -- restrict search to the current working directory dirs = { root }, -- Only show for markdown files glob = '*.md', exclude = exclude_patterns, -- include files ignored by .gitignore args = { '--no-ignore' }, -- Start in normal mode on_show = function() vim.cmd.stopinsert() end, finder = 'grep', format = 'file', show_empty = true, supports_live = false, layout = 'ivy_split', } end, desc = 'Search for incomplete tasks', },Searching completed todo:
{ '<leader>Tc', function() local root = Util.root.get() local exclude_dirs = { 'Templates', 'node_modules', '.git', 'dist', 'build', } local exclude_patterns = vim.tbl_map(function(dir) return '**/' .. dir .. '/**' end, exclude_dirs) Snacks.picker.grep { prompt = ' ', -- search = "^\\s*- \\[x\\] `done:", search = '^\\s*- \\[[xX]\\](?: `done:)?', regex = true, -- no “live grep” needed here since we have a fixed pattern live = false, -- restrict search to the current working directory dirs = { root }, -- exclude directories exclude = exclude_patterns, -- include files ignored by .gitignore args = { '--no-ignore' }, -- Start in normal mode on_show = function() vim.cmd.stopinsert() end, finder = 'grep', format = 'file', show_empty = true, supports_live = false, layout = 'ivy', } end, desc = 'Search for complete tasks', }, },lua/util/root.lua:Additional context
No response