Compare commits

...

2 Commits

@ -0,0 +1,75 @@
# Todoer.nvim - Enhanced TODO Management for Neovim
A Neovim plugin that provides enhanced TODO list management with smart handling of checkboxes, indentation, and list items in markdown and other text formats.
## Features
✅ **Current Functionality:**
- Smart TODO item creation with `<leader>ti`, `<leader>ta`, `<leader>to`
- Toggle checkboxes with `<leader>tt`
- Remove TODO markup with `<leader>td`
- Smart Enter key handling in insert mode:
- Creates new TODO items with proper indentation
- Handles empty TODO items by outdenting or terminating lists
- Tab/Shift-Tab indentation for TODO items
- Supports multiple list markers: `-`, `*`, `+`
- Works with markdown, text, and norg files by default
## Known Issues
🐛 **Current Bugs:**
- Tab indentation handling still uses feedkeys and needs refactoring
- Shift-Tab behavior may not be consistent with spaces vs tabs
- Edge cases with mixed indentation (spaces + tabs) not fully handled
- Cursor positioning could be improved in some scenarios
## Roadmap
📌 **Planned Improvements:**
- [ ] Refactor tab indentation to use proper buffer operations
- [ ] Add support for numbered lists
- [ ] Add support for nested TODO items with proper indentation
- [ ] Add visual selection operations for multiple TODOs
- [ ] Add commands for archiving completed items
- [ ] Add support for custom TODO markers
- [ ] Add support for custom checkbox states (e.g., `[ ]`, `[x]`, `[-]`)
## Installation
Using [lazy.nvim](https://github.com/folke/lazy.nvim):
```lua
{
'your-username/todoer.nvim',
config = function()
require('todoer').setup({
-- Optional: override default filetypes
filetypes = { 'markdown', 'text', 'norg' }
})
end
}
```
## Configuration
Default configuration:
```lua
{
filetypes = { "markdown", "text", "norg" } -- Filetypes to activate the plugin for
}
```
## Keybindings
Normal Mode:
- `<leader>ti` - Convert line to TODO (cursor after `] `)
- `<leader>ta` - Convert line to TODO (cursor at end)
- `<leader>to` - Insert new TODO line below
- `<leader>tt` - Toggle checkbox state
- `<leader>td` - Remove TODO markup
Insert Mode:
- `<CR>` - Smart enter behavior for TODO items
- `<Tab>` - Indent TODO item
- `<S-Tab>` - Outdent TODO item

@ -70,6 +70,13 @@ local function get_line_details(lnum)
end end
-- Helper: Creates proper indent string based on buffer settings
local function get_indent_string()
local sw = vim.bo.shiftwidth
local et = vim.bo.expandtab
return et and string.rep(" ", sw) or "\t"
end
-- Helper: Gets details for the current line including cursor position -- Helper: Gets details for the current line including cursor position
local function get_current_line_details_with_cursor() local function get_current_line_details_with_cursor()
local cursor_pos = vim.api.nvim_win_get_cursor(0) local cursor_pos = vim.api.nvim_win_get_cursor(0)
@ -266,34 +273,45 @@ local function setup_buffer_keymaps()
end end
end end
-- indent line if tab is pressed when line is a todo (Will be refactored in Step 4) -- Handle tab indentation for TODO lines
local function press_tab() local function press_tab()
local current_line = vim.api.nvim_get_current_line() local details = get_line_details(vim.api.nvim_win_get_cursor(0)[1])
-- Updated pattern to match -, *, + markers if not details or not details.is_todo then
local pattern = "^%s*[%-%*%+]%s+%[[ x]%]"
if string.match(current_line, pattern) then
-- Still using feedkeys for now, will be refactored later
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-t>", true, false, true), "i", false)
return "" -- Action handled by feedkeys
else
-- Return <Tab> to allow default behavior
return vim.api.nvim_replace_termcodes("<Tab>", true, false, true) return vim.api.nvim_replace_termcodes("<Tab>", true, false, true)
end end
local indent_str = get_indent_string()
local new_line = details.indent .. indent_str ..
(details.marker or "-") .. " [ ] " .. details.content
vim.api.nvim_set_current_line(new_line)
-- Calculate new cursor column (preserve relative position)
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
local new_col = cursor_col + #indent_str
vim.api.nvim_win_set_cursor(0, {vim.api.nvim_win_get_cursor(0)[1], new_col})
return "" -- Prevent default behavior
end end
-- indent line if shift tab is pressed when line is a todo (Will be refactored in Step 4) -- Handle shift-tab outdentation for TODO lines
local function press_shift_tab() local function press_shift_tab()
local current_line = vim.api.nvim_get_current_line() local details = get_line_details(vim.api.nvim_win_get_cursor(0)[1])
-- Updated pattern to match -, *, + markers if not details or not details.is_todo or #details.indent == 0 then
local pattern = "^%s*[%-%*%+]%s+%[[ x]%]"
if string.match(current_line, pattern) then
-- Still using feedkeys for now, will be refactored later
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-d>", true, false, true), "i", false)
return "" -- Action handled by feedkeys
else
-- Return <S-Tab> to allow default behavior
return vim.api.nvim_replace_termcodes("<S-Tab>", true, false, true) return vim.api.nvim_replace_termcodes("<S-Tab>", true, false, true)
end end
local sw = vim.bo.shiftwidth
local new_indent = details.indent:sub(1, -sw - 1)
local new_line = new_indent ..
(details.marker or "-") .. " [ ] " .. details.content
vim.api.nvim_set_current_line(new_line)
-- Calculate new cursor column (preserve relative position)
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
local new_col = math.max(0, cursor_col - sw)
vim.api.nvim_win_set_cursor(0, {vim.api.nvim_win_get_cursor(0)[1], new_col})
return "" -- Prevent default behavior
end end
-- Toggles the checkbox [ ] <-> [x] for lines starting with -, *, +, or # -- Toggles the checkbox [ ] <-> [x] for lines starting with -, *, +, or #
@ -322,9 +340,9 @@ local function setup_buffer_keymaps()
vim.keymap.set("n", "<leader>t", function() end, { desc = "+TODOs", buffer = 0 }) -- Placeholder vim.keymap.set("n", "<leader>t", function() end, { desc = "+TODOs", buffer = 0 }) -- Placeholder
-- Keep <CR> mapping without expr = true -- Keep <CR> mapping without expr = true
vim.keymap.set("i", "<CR>", press_enter, { desc = "Todoer: Handle Enter", buffer = 0 }) vim.keymap.set("i", "<CR>", press_enter, { desc = "Todoer: Handle Enter", buffer = 0 })
-- Keep expr = true for Tab/S-Tab for now, until they are refactored -- Tab handling for TODO items
vim.keymap.set("i", "<TAB>", press_tab, { desc = "Todoer: Handle Tab", expr = true, buffer = 0 }) vim.keymap.set("i", "<TAB>", press_tab, { desc = "Todoer: Handle Tab", buffer = 0 })
vim.keymap.set("i", "<S-Tab>", press_shift_tab, { desc = "Todoer: Handle Shift-Tab", expr = true, buffer = 0 }) vim.keymap.set("i", "<S-Tab>", press_shift_tab, { desc = "Todoer: Handle Shift-Tab", buffer = 0 })
vim.keymap.set("n", "<leader>tt", toggle_todo, { desc = "Todoer: Toggle TODO", buffer = 0 }) vim.keymap.set("n", "<leader>tt", toggle_todo, { desc = "Todoer: Toggle TODO", buffer = 0 })
-- New mappings for adding TODOs -- New mappings for adding TODOs
vim.keymap.set("n", "<leader>ti", add_todo_insert_mode, { desc = "Todoer: Add TODO (cursor after marker)", buffer = 0, silent = true }) vim.keymap.set("n", "<leader>ti", add_todo_insert_mode, { desc = "Todoer: Add TODO (cursor after marker)", buffer = 0, silent = true })

Loading…
Cancel
Save