1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
--[[ 50-markdown.lua — treesitter parsers, markdown rendering, and checklist commands.
Renders markdown via `render-markdown`
(https://github.com/MeanderingProgrammer/render-markdown.nvim).
User commands:
MarkdownCheck: check the checklist item under the cursor and strike through its text
MarkdownUncheck: uncheck the checklist item under the cursor and remove the strikethrough
]]
----------------------------------------------------------------------------------------------------
-- Rendering ---------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
require("nvim-treesitter").install({
"html",
"latex",
"markdown",
"markdown_inline",
"yaml",
})
require("render-markdown").setup({
code = {
position = "center",
sign = false,
width = "block",
min_width = 60,
},
win_options = { conceallevel = { rendered = 2 } },
})
----------------------------------------------------------------------------------------------------
-- Checklist ---------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
--[[ Locate the checklist item containing line `row`, returning its first and last line (1-indexed).
Walks up from `row` to the item's `- [ ]` bullet — any other bullet, or an unindented non-blank
line, means `row` is not in a checklist item — then down through the item's continuation lines
(blank, or indented to the bullet's content column). Returns nil when `row` is outside an item. ]]
local function item_range(lines, row)
local first = row
while lines[first] and not lines[first]:match("^%s*%- %[[ Xx]%] ") do
if lines[first]:match("^%s*%- ") or lines[first]:match("^%S") then
return
end
first = first - 1
end
if not lines[first] then
return
end
local content_col = #lines[first]:match("^%s*") + 2
local last = first
for i = first + 1, #lines do
local line = lines[i]
if line:match("^%s*%- ") or (line:match("%S") and #line:match("^%s*") < content_col) then
break
end
if line:match("%S") then
last = i
end
end
if last < row then
return
end
return first, last
end
-- Strike through the text of `line` after `prefix`, keeping a trailing hard-break `\` outside.
local function strike(line, prefix)
return (line:gsub("^(" .. prefix .. ")(.-)(%s*\\?)$", "%1~%2~%3"))
end
-- Remove the strikethrough around the text of `line` after `prefix`, if there is one.
local function unstrike(line, prefix)
return (line:gsub("^(" .. prefix .. ")~(.-)~(%s*\\?)$", "%1%2%3"))
end
--[[ Check or uncheck the checklist item under the cursor.
Checking flips the bullet's `[ ]` to `[X]` and strikes through each non-blank line of the item;
unchecking reverses both. Does nothing when the cursor is not in a checklist item or the item is
already in the requested state. ]]
local function set_item(checked)
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
local first, last = item_range(lines, vim.api.nvim_win_get_cursor(0)[1])
local marker = checked and "^%s*%- %[ %] " or "^%s*%- %[[Xx]%] "
if not (first and last) or not lines[first]:match(marker) then
return
end
local restyle = checked and strike or unstrike
local item = {}
for i = first, last do
local line = lines[i]
if i == first then
line = restyle(line:gsub("%[.%]", checked and "[X]" or "[ ]", 1), "%s*%- %[.%] ")
elseif line:match("%S") then
line = restyle(line, "%s*")
end
item[#item + 1] = line
end
vim.api.nvim_buf_set_lines(0, first - 1, last, false, item)
end
----------------------------------------------------------------------------------------------------
-- Commands ----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- Check the checklist item under the cursor.
local function check_item()
set_item(true)
end
-- Uncheck the checklist item under the cursor.
local function uncheck_item()
set_item(false)
end
vim.api.nvim_create_user_command("MarkdownCheck", check_item, { desc = "Check checklist item" })
vim.api.nvim_create_user_command(
"MarkdownUncheck",
uncheck_item,
{ desc = "Uncheck checklist item" }
)
|