|
1 | 1 | local Files = require('orgmode.parser.files')
|
2 | 2 | local config = require('orgmode.config')
|
| 3 | +local utils = require('orgmode.utils') |
| 4 | + |
| 5 | +local cookie_namespace = vim.api.nvim_create_namespace('orgmode-cookies') |
| 6 | +local cookie_query = vim.treesitter.parse_query('org', '(cookie) @cookie') |
| 7 | +local checkbox_query = vim.treesitter.parse_query('org', '(list (listitem (checkbox) @checkbox))') |
| 8 | +local list_in_body_query = vim.treesitter.parse_query('org', '(body (list) @list)') |
3 | 9 |
|
4 | 10 | local function load_code_blocks()
|
5 | 11 | local file = vim.api.nvim_buf_get_name(0)
|
@@ -36,7 +42,73 @@ local function add_todo_keywords_to_spellgood()
|
36 | 42 | end
|
37 | 43 | end
|
38 | 44 |
|
| 45 | +local function _display_cookie_virt_text(cookie, checked, total) |
| 46 | + local row, column = cookie:start() |
| 47 | + local cookie_text = vim.treesitter.get_node_text(cookie, 0) |
| 48 | + |
| 49 | + -- TODO: fix this in treesitter |
| 50 | + local _, leading_spaces = cookie_text:find('^%s+') |
| 51 | + cookie_text = vim.trim(cookie_text) |
| 52 | + |
| 53 | + local text |
| 54 | + if cookie_text == '[/]' then |
| 55 | + text = string.format('[%d/%d]', checked, total) |
| 56 | + else |
| 57 | + text = string.format('[%d%%]', (100 * checked) / total) |
| 58 | + end |
| 59 | + vim.api.nvim_buf_set_extmark(0, cookie_namespace, row, column + (leading_spaces or 0), { |
| 60 | + -- TODO: make highlight group configurable |
| 61 | + virt_text = { { text, 'Error' } }, |
| 62 | + virt_text_pos = 'overlay', |
| 63 | + hl_mode = 'combine', |
| 64 | + }) |
| 65 | +end |
| 66 | + |
| 67 | +local function _get_cookie_checked_and_total(parent) |
| 68 | + local parent_type = parent:type() |
| 69 | + local start_row, _, end_row, _ = parent:range() |
| 70 | + local checked, total = 0, 0 |
| 71 | + for _, checkbox in checkbox_query:iter_captures(parent, 0, start_row, end_row + 1) do |
| 72 | + local closest_parent = utils.get_closest_parent_of_type(checkbox, parent_type) |
| 73 | + if closest_parent and closest_parent == parent then -- only count direct children |
| 74 | + local checkbox_text = vim.treesitter.get_node_text(checkbox, 0) |
| 75 | + if checkbox_text:match('%[[x|X]%]') then |
| 76 | + checked = checked + 1 |
| 77 | + end |
| 78 | + total = total + 1 |
| 79 | + end |
| 80 | + end |
| 81 | + |
| 82 | + return checked, total |
| 83 | +end |
| 84 | + |
| 85 | +local function add_cookies() |
| 86 | + local parser = vim.treesitter.get_parser(0, 'org') |
| 87 | + local root = parser:parse()[1]:root() |
| 88 | + |
| 89 | + vim.api.nvim_buf_clear_namespace(0, cookie_namespace, 0, -1) |
| 90 | + |
| 91 | + for _, cookie in cookie_query:iter_captures(root, 0, 0, -1) do |
| 92 | + local parent = cookie:parent() |
| 93 | + local checked, total = 0, 0 |
| 94 | + if parent:type() == 'headline' then |
| 95 | + parent = parent:parent() |
| 96 | + local start_row, _, end_row, _ = parent:range() |
| 97 | + for _, list in list_in_body_query:iter_captures(parent, 0, start_row, end_row + 1) do |
| 98 | + local c_checked, c_total = _get_cookie_checked_and_total(list) |
| 99 | + checked = checked + c_checked |
| 100 | + total = total + c_total |
| 101 | + end |
| 102 | + else |
| 103 | + checked, total = _get_cookie_checked_and_total(parent) |
| 104 | + end |
| 105 | + |
| 106 | + _display_cookie_virt_text(cookie, checked, total) |
| 107 | + end |
| 108 | +end |
| 109 | + |
39 | 110 | return {
|
40 | 111 | load_code_blocks = load_code_blocks,
|
41 | 112 | add_todo_keywords_to_spellgood = add_todo_keywords_to_spellgood,
|
| 113 | + add_cookies = add_cookies, |
42 | 114 | }
|
0 commit comments