1
0

Compare commits

...

10 Commits

Author SHA1 Message Date
Stefan Rakel
f63cd19d22 Change licens to BSD 3 clause 2025-09-21 20:37:10 +02:00
Stefan Rakel
de332271d3 Allow definition of checkmark characters 2024-08-09 14:59:03 +02:00
Stefan Rakel
1d7f44983c Fix linter errors 2023-12-11 14:16:23 +01:00
Stefan Rakel
cd92ad32ce Also ignore less indented siblings for find children 2023-10-27 12:16:03 +02:00
Stefan Rakel
ef4aa8a52a Fix wrong findChildren logic skipping over siblings 2023-10-27 12:14:02 +02:00
Stefan Rakel
eac03a0592 Add more details to the readme 2023-10-27 11:02:08 +02:00
Stefan Rakel
c1548f9688 Add Readme 2023-10-27 10:59:19 +02:00
Stefan Rakel
23ba85a5fc Add helpfile 2023-10-27 10:54:03 +02:00
Stefan Rakel
3b449c72a3 Move lua code to lua folder 2023-10-27 10:06:08 +02:00
Stefan Rakel
47c9f1eb74 Create checkbox plugin from script in my personal config 2023-10-27 09:43:17 +02:00
5 changed files with 367 additions and 17 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
tags
test.md

24
LICENSE
View File

@@ -1,21 +1,11 @@
MIT License
Copyright 2025 Stefan Rakel
Copyright (c) 2023 Stefan Rakel
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

58
README.md Normal file
View File

@@ -0,0 +1,58 @@
# checkbox.nvim
## Introduction
This plugin provides an easy way to toggle nested checkboxes of the form:
```markdown
[ ] item
* [ ] item
- [X] item
```
Parent and child items are updated automatically when a checkbox is changed. It
is easily configurable what may come before the checkbox. Configuring what is
skipped when searching for parents and child checkboxes alike is also possible.
## Installation
Use your preferred plugin manager and add
```
"ibutra/checkbox.nvim"
```
as plugin.
## Usage
Add a mapping to the provided function:
```lua
vim.keymap.set("n", "<leader>x", require("checkbox").checkbox)
```
For further details and configuration options see the documentation:
[Vim Helpfile](doc/checkbox.nvim.txt)
## License
```
MIT License
Copyright (c) 2023 Stefan Rakel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```

111
doc/checkbox.nvim.txt Normal file
View File

@@ -0,0 +1,111 @@
*checkbox.nvim.txt* Easily toggle checklist items
1. Introduction ....................................... |checkbox-introduction|
2. Usage ..................................................... |checkbox-usage|
3. Configuration ..................................... |checkbox-configuration|
3.1 g:checkbox_prefixPatterns ..................... |checkbox-prefixPatterns|
3.2 g:checkbox_skipPatterns ......................... |checkbox-skipPatterns|
4. Changelog ............................................. |checkbox-changelog|
5. License ................................................. |checkbox-license|
==============================================================================
1. Introduction *checkbox-introduction*
checkbox.nvim is a simple plugin that switches checkbox items of the form
>
[ ] item
[X] item
[X] item
* [ ] item
- [X] item
1. [ ] item
<
It also allows automatic adding of a checkbox to a line.
Furthermore it supports nested checkboxes and updates parents and children
alike.
==============================================================================
2. Usage *checkbox-usage*
To use the plugin bind a mapping to the returned function in the table:
>
vim.keymap.set("n", "<leader>x", require("checkbox").checkbox)
<
This will toggle the current line's checkbox or add one if not present.
This function will also update parent and child items to the following rules:
If a checkbox is checked, all its children are checked as well. If a chekcbox
is unchecked, all its children are unchecked as well.
The parent of the changed checkbox will get updated. It will be set to checked
if all its children are checked and to unchecked otherwise.
==============================================================================
3. Configuration *checkbox-configuration*
The following variables change the behaviour of this plugin:
------------------------------------------------------------------------------
3.1 g:checkbox_prefixPatterns *checkbox-prefixPatterns*
list
default: {"%-", "%*", "#+", "%->", "=>", "%d+%."}
Set this option to lua patterns which come before the checkbox `[ ]`. I.e. >
vim.g.checkbox_prefixPatterns = {"%-", "%*", "%d+%."}
Will create the checkbox after a `-`, `*` and `1.` item: >
- [ ] item
* [ ] item
12. [] item
------------------------------------------------------------------------------
3.1 g:checkbox_skipPatterns *checkbox-skipPatterns*
list
default:{"%-", "%*", "%->", "=>", "%d+%."}
Set this option to lua patterns which will be ignored when searching for
parents and children. I.e. >
vim.g.checkbox_skipPatterns = {"%-", "%*", "%->", "=>"}
Will make checkbox.nvim consider all checkboxes in the following example as
connected: >
[ ] Root-Parent
-> Some note
[ ] Child-Item to Root
- Another note
[ ] Another Child to Root
* Bullets under todo item
* another bullet
[ ] Child-Parent
=> More info
* [ ] Child
* [ ] Child
==============================================================================
4. Changelog *checkbox-changelog*
2023.10.27
* First release
==============================================================================
5. License *checkbox-license*
MIT License
Copyright (c) 2023 Stefan Rakel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

189
lua/checkbox.lua Normal file
View File

@@ -0,0 +1,189 @@
-- MIT License
--
-- Copyright (c) 2023 Stefan Rakel
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
-- Initialize patterns
local prefixPatterns = {"%-", "%*", "#+", "%->", "=>", "%d+%."}
local skipPatterns = {"%-", "%*", "%->", "=>", "%d+%."}
local checkmarks = {"X", "x"} --UTF8 characters currently not supported
if vim.g.checkbox_prefixPatterns then
prefixPatterns = vim.g.checkbox_prefixPatterns
end
if vim.g.checkbox_skipPatterns then
prefixPatterns = vim.g.checkbox_skipPatterns
end
-- returns indentation level, checked status and text if the line has a checbox
-- nil otherwise
local function getCheckboxFromLine(lineNum)
local line = vim.fn.getline(lineNum)
for _, pat in ipairs(prefixPatterns) do
local pattern = "(%s*)(" .. pat .. "%s*)%[([ " .. vim.fn.join(checkmarks, "") .."]?)%](.*)"
local whitespace, before, checked, after = string.match(line, pattern)
if whitespace then
for _, c in ipairs(checkmarks) do
if checked == c then
checked = true
end
end
if checked ~= true then
checked = false
end
whitespace = string.gsub(whitespace, "\t", " ")
local indentation = string.len(whitespace)
return {lineNum=lineNum, indentation=indentation, checked=checked, before=before, after=after}
end
end
return nil
end
local function writeCheckbox(checkbox)
local checkedString = " "
if checkbox.checked then
checkedString = checkmarks[1]
end
local newLine = string.rep(" ", checkbox.indentation) .. checkbox.before .. "[" .. checkedString .. "]" .. checkbox.after
vim.fn.setline(checkbox.lineNum, newLine)
end
local function setCheckbox(checkbox, checked)
checkbox.checked = checked
writeCheckbox(checkbox)
end
local function switchOrAddCheckbox(lineNum)
local checkbox = getCheckboxFromLine(lineNum)
if checkbox then
checkbox.checked = not checkbox.checked
writeCheckbox(checkbox)
return checkbox
else
for _, pat in ipairs(prefixPatterns) do
local pattern = "(%s*" .. pat .. "%s*)(.*)"
local before, after = string.match(vim.fn.getline(lineNum), pattern)
if before then
local newLine = before .. "[ ] " .. after
vim.fn.setline(lineNum, newLine)
return getCheckboxFromLine(lineNum)
end
end
return nil
end
end
local function findParent(startCheckbox)
if not startCheckbox then
return false
end
local lineNum = startCheckbox.lineNum
while true do
lineNum = lineNum - 1
local checkbox = getCheckboxFromLine(lineNum)
if not checkbox then
--check skip patterns
local skipped = false
for _, pat in ipairs(skipPatterns) do
if string.match(vim.fn.getline(lineNum), "%s*" .. pat .. ".*") then
skipped = true
end
end
if not skipped then
return false
end
else
if checkbox.indentation < startCheckbox.indentation then
return checkbox
end
end
end
end
local function findChildren(startCheckbox)
if not startCheckbox then
return false
end
local children = {}
local lineNum = startCheckbox.lineNum
while true do
lineNum = lineNum + 1
local checkbox = getCheckboxFromLine(lineNum)
if not checkbox then
--check skip patterns
local skipped = false
for _, pat in ipairs(skipPatterns) do
if string.match(vim.fn.getline(lineNum), "%s*" .. pat .. ".*") then
skipped = true
end
end
if not skipped then
return children
end
elseif checkbox.indentation <= startCheckbox.indentation then
return children
elseif checkbox.indentation > startCheckbox.indentation then
table.insert(children, checkbox)
end
end
end
local function updateFromChildren(checkbox)
local children = findChildren(checkbox)
if not children then
return
end
for _, child in ipairs(children) do
if not child.checked then
setCheckbox(checkbox, false)
return
end
end
setCheckbox(checkbox, true)
end
local function updateChildren(checkbox)
local children = findChildren(checkbox)
if not children then
return
end
for _, child in ipairs(children) do
setCheckbox(child, checkbox.checked)
end
end
local function switchAndUpdateCheckbox()
local lineNum = vim.fn.line(".")
local checkbox = switchOrAddCheckbox(lineNum)
if checkbox then
-- Update children
updateChildren(checkbox)
-- Traverse parents upwards and update them
local parent = findParent(checkbox)
while parent do
updateFromChildren(parent)
parent = findParent(parent)
end
end
end
return {
checkbox = switchAndUpdateCheckbox
}