vim.opt_local.tabstop = 2 -- CommonMark expects two spaces for indentation vim.opt_local.shiftwidth = 0 vim.opt_local.softtabstop = -1 vim.opt_local.expandtab = true -- Change tabs to spaces -- Nothing in the gutter, except sign columns if necessary vim.opt_local.number = false vim.opt_local.relativenumber = false vim.opt_local.signcolumn = "auto" vim.opt_local.foldcolumn = "0" -- vim.opt_local.textwidth = vim.g.dotfiles.textwidth.markdown -- gw wraps at this value -- There is a bug where folded fenced code blocks will be completely invisible -- But (apparently) it only happen when there is a # heading (and no ## heading, no ### heading etc) -- Probably caused by tree-sitter parsing, but it's not really a problem, since adding a ## heading fixes it -- Just remember this and don't try to fix it again! vim.opt_local.foldlevel = 1 vim.opt_local.complete = { "o", -- 'omnifunc' ".", -- current buffer } -- Visible link labels vim.api.nvim_set_hl(0, "@markup.link.label.markdown_inline", { underline = true, update = true }) vim.b.format = true -- See plugin/50-format.lua local function item_range() local cursor_row = vim.api.nvim_win_get_cursor(0)[1] local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) -- Walk up to the task bullet. Any other bullet, or a line that's neither -- blank nor indented, means we're not inside a task item. local start_row = cursor_row while start_row >= 1 do local line = lines[start_row] if line:match("^%s*%- %[[ Xx]%] ") then break end if line:match("^%s*%- ") then return nil end if not (line:match("^%s*$") or line:match("^%s+%S")) then return nil end start_row = start_row - 1 end if start_row < 1 then return nil end -- Walk down through continuation paragraphs. Blank lines are inside the -- item as long as a later line is still indented to the content column. local bullet_indent = #lines[start_row]:match("^(%s*)") local cont_min = bullet_indent + 2 local end_row = start_row for r = start_row + 1, #lines do local line = lines[r] if line:match("^%s*$") then -- blank, keep scanning elseif line:match("^%s*%- ") then break elseif #line:match("^(%s*)") < cont_min then break else end_row = r end end return start_row, end_row end local function check_checklist_item() local start_row, end_row = item_range() if not (start_row and end_row) then return end local lines = vim.api.nvim_buf_get_lines(0, start_row - 1, end_row, false) if not lines[1]:match("^%s*%- %[ %] ") then return end for i, line in ipairs(lines) do if i == 1 then lines[i] = line:gsub("^(%s*%- )%[ %] (.-)(%s*\\?)$", "%1[X] ~%2~%3", 1) elseif not line:match("^%s*$") then lines[i] = line:gsub("^(%s*)(.-)(%s*\\?)$", "%1~%2~%3", 1) end end vim.api.nvim_buf_set_lines(0, start_row - 1, end_row, false, lines) end local function uncheck_checklist_item() local start_row, end_row = item_range() if not (start_row and end_row) then return end local lines = vim.api.nvim_buf_get_lines(0, start_row - 1, end_row, false) if not lines[1]:match("^%s*%- %[X%] ") then return end for i, line in ipairs(lines) do if i == 1 then lines[i] = line:gsub("%[X%]", "[ ]", 1):gsub("~", "", 2) elseif not line:match("^%s*$") then lines[i] = line:gsub("~", "", 2) end end vim.api.nvim_buf_set_lines(0, start_row - 1, end_row, false, lines) end vim.api.nvim_buf_create_user_command(0, "MarkdownCheck", check_checklist_item, { desc = "Check checklist item" }) vim.api.nvim_buf_create_user_command(0, "MarkdownUncheck", uncheck_checklist_item, { desc = "Uncheck checklist item" })