A lua version of todotxt.vim with enhanced functionality for managing todo.txt files in Neovim.
- File Management: Toggle between todo.txt and done.txt files in floating windows
- Task Operations: Mark tasks as complete/incomplete, cycle task priorities (A-C)
- New Task Creation: Quick task capture with automatic date formatting
- Task Organization: Multiple sorting options (priority, context, project, due date)
- Task Movement: Automatically move completed tasks to done.txt file
- Ghost Text: Visual priority hints with customizable mappings and toggle support
- Treesitter Support: Enhanced syntax highlighting with todotxt parser
- In-process LSP: Completion, formatting, code actions, references, and rename
Using vim.pack:
vim.pack.add({ "https://github.com/phrmendes/todotxt.nvim" })Add these options:
vim.filetype.add({
filename = {
["todo.txt"] = "todotxt",
["done.txt"] = "todotxt",
},
})For enhanced functionality (like syntax highlighting), the nvim-treesitter plugin with the todotxt parser is recommended:
vim.pack.add({ src = "https://github.com/nvim-treesitter/nvim-treesitter", version = "main"})
require("nvim-treesitter").install({ "todotxt" })require("todotxt").setup({
todotxt = vim.env.HOME .. "/Documents/notes/todo.txt",
donetxt = vim.env.HOME .. "/Documents/notes/done.txt",
max_priority = "C",
metadata = {
-- asc/desc strings
tag = { sort = "asc" },
due = { sort = "desc" },
-- custom comparator: a comes before b if tonumber(a) < tonumber(b)
effort = { sort = function(a, b) return tonumber(a) < tonumber(b) end },
},
ghost_text = {
enable = true,
mappings = {
["(A)"] = "today",
["(B)"] = "tomorrow",
["(C)"] = "this week",
},
},
})Suggested keybindings:
vim.keymap.set("n", "<leader>tn", "<cmd>TodoTxt new<cr>", { desc = "New todo entry" })
vim.keymap.set("n", "<leader>tt", "<cmd>TodoTxt<cr>", { desc = "Toggle todo.txt" })
vim.keymap.set("n", "<leader>td", "<cmd>DoneTxt<cr>", { desc = "Toggle done.txt" })
vim.keymap.set("n", "<leader>tg", "<cmd>TodoTxt ghost<cr>", { desc = "Toggle ghost text" })Sort, toggle done, cycle priority, and move done are available as LSP code
actions (<leader>a).
The default path for todo.txt is ~/Documents/notes/todo.txt. Check the help file for more information.
An in-process LSP server starts automatically when opening a todotxt buffer. Disable it with lsp = false in setup:
require("todotxt").setup({ lsp = false })Trigger characters restrict suggestions by category:
| Trigger | Shows |
|---|---|
( |
Priorities (A), (B), (C) |
+ |
Projects +myproject |
@ |
Contexts @home |
Manual (<C-x><C-o>) |
All categories + key: values |
The trigger character is replaced when a suggestion is accepted (prevents doubled prefixes).
vim.lsp.buf.format() rewrites each line to canonical form:
x (A) 2025-06-15 2025-01-01 desc due:2025-06-01 @ctx +proj
Order: completion marker, priority, completion date, creation date, description, key:value pairs, contexts, projects.
Available via vim.lsp.buf.code_action():
- Toggle done — mark/unmark task as completed
- Cycle priority — advance to next priority letter
- Sort tasks — default sort (priority, then alphabetical)
- Sort by priority / project / context / due date
Each key in config.metadata also appears as a Sort by {key} action,
using the sort strategy defined in its config ("asc", "desc", or a
custom comparator).
Find all occurrences of a +project or @context tag in the buffer.
Rename a +project or @context across every occurrence in the buffer.
The ghost text feature displays visual hints next to tasks based on their priority levels. This can be customized with your own mappings:
ghost_text = {
enable = true,
mappings = {
["(A)"] = "today",
["(B)"] = "tomorrow",
["(C)"] = "this week",
},
prefix = " ", -- Text prefix
highlight = "Comment", -- Highlight group
}You can toggle ghost text on/off using :TodoTxt ghost or the suggested keybinding.
:TodoTxt- Toggle todo.txt file in floating window:TodoTxt new- Create a new todo entry:TodoTxt ghost- Toggle ghost text display:DoneTxt- Toggle done.txt file in floating window