Skip to content

Commit 9f8b4d8

Browse files
committed
feat(cookie): implement virtual cookies
Closes #745
1 parent 32ef9e9 commit 9f8b4d8

File tree

8 files changed

+360
-21
lines changed

8 files changed

+360
-21
lines changed

docs/configuration.org

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,3 +3012,30 @@ require('orgmode').setup({
30123012
#+end_src
30133013

30143014
📝 NOTE: If you are using a plugin for =vim.ui.input=, make sure it supports autocompletion for better experience. [[https://github.com/folke/snacks.nvim][snacks.nvim]] input module supports autocompletion.
3015+
3016+
*** cookies_use_extmarks
3017+
:PROPERTIES:
3018+
:CUSTOM_ID: cookies_use_extmarks
3019+
:END:
3020+
- Type: =boolean=
3021+
- Default: =false=
3022+
Possible values:
3023+
- =true= - Uses /Virtual/ cookies to show live progress for cookies overlayed on top of the actual cookie text.
3024+
- =false= - Do not add any /Virtual/ cookies.
3025+
3026+
You can toggle Virtual cookies on the fly by executing command =:Org cookie_mode= when in a org buffer.
3027+
This additionally sets the buffer variable =vim.b.org_cookie_mode= to =true= or =false=, depending on the current state.
3028+
3029+
Currently this only applies Virtual cookies to headlines.
3030+
3031+
Uses the following highlights:
3032+
- [email protected]~: The highlight to use for the delimiters (brackets: ~[~ & ~]~)
3033+
- [email protected]~: A more granular highlight for just the left ~[~ bracket
3034+
- [email protected]~: A more granular highlight for just the right ~]~ bracket
3035+
- [email protected]~: The numbers used in the cookie (~50~)
3036+
- ~org.cookie.number.complete~: A more granular highlight for the left side of ~[1/5]~ (in this case the ~1~)
3037+
- ~org.cookie.number.total~: A more granular highlight for the right side of ~[1/5]~ (in this case the ~5~)
3038+
- [email protected]~: The sign used in the cookie (e.g. ~/~, ~%~, or ~???~)
3039+
- [email protected]~: More granular if there wasn't items to calculate on (~???~) and you want a different highlight for the unknown sign
3040+
- [email protected]~: More granular for the div sign, the ~/~ in ~[1/5]~
3041+
- [email protected]~: More granular for the percent sign, the ~%~ in ~[100%]~

ftplugin/org.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ if config.org_startup_indented then
1818
require('orgmode.ui.virtual_indent'):new(bufnr):attach()
1919
end
2020

21+
if config.ui.cookies_use_extmarks then
22+
require('orgmode.ui.virtcookie').new(bufnr):attach()
23+
end
24+
2125
vim.bo.modeline = false
2226
vim.opt_local.fillchars:append('fold: ')
2327
vim.opt_local.foldmethod = 'expr'

lua/orgmode/colors/highlights.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ function M.link_highlights()
7171
['@org.table.delimiter'] = '@punctuation.special',
7272
['@org.table.heading'] = '@markup.heading',
7373
['@org.edit_src'] = 'Visual',
74+
75+
-- For cookie extmarks (applicable if enabled)
76+
['@org.cookie.delimiter'] = 'Delimiter',
77+
['@org.cookie.sign'] = 'Special',
78+
['@org.cookie.number'] = 'Number',
7479
}
7580

7681
for src, def in pairs(links) do

lua/orgmode/config/_meta.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@
174174
---@field folds? { colored: boolean } Should folds be colored or use the default folding highlight. Default: { colored: true }
175175
---@field menu? { handler: fun() | nil } Menu configuration
176176
---@field input? { use_vim_ui: boolean } Input configuration
177+
---@field cookies_use_extmarks? boolean Should virtual text/extmarks be used for headline cookie progress
177178

178179
---@class OrgMappingsConfig
179180
---@field disable_all? boolean Disable all mappings. Default: false

lua/orgmode/config/defaults.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ local DefaultConfig = {
221221
input = {
222222
use_vim_ui = false,
223223
},
224+
cookies_use_extmarks = false,
224225
},
225226
}
226227

lua/orgmode/files/headline.lua

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -903,22 +903,16 @@ function Headline:_set_cookie(cookie, num, denum)
903903
return self:_set_node_text(cookie, new_cookie_val)
904904
end
905905

906-
function Headline:update_cookie()
907-
-- Update cookie state from a check box state change
908-
909-
-- Return early if the headline doesn't have a cookie
910-
local cookie = self:get_cookie()
911-
if not cookie then
912-
return self
913-
end
914-
906+
---@return { [1]: integer, [2]: integer }? checked_unchecked The first integer is the number of checked boxes, the second integer is the total boxes
907+
function Headline:_get_checkbox_progress()
908+
-- Count done checkboxes and total checkboxes for the headline
915909
local section = self:node():parent()
910+
local num_checked_boxes, num_boxes = 0, 0
916911
if not section then
917-
return self
912+
return
918913
end
919914

920915
-- Count checked boxes from all lists
921-
local num_checked_boxes, num_boxes = 0, 0
922916
local body = section:field('body')[1]
923917
if body then
924918
for node in body:iter_children() do
@@ -933,6 +927,53 @@ function Headline:update_cookie()
933927
end
934928
end
935929

930+
if num_boxes == 0 then
931+
return
932+
end
933+
934+
return { num_checked_boxes, num_boxes }
935+
end
936+
937+
---@return { [1]: integer, [2]: integer }? done_total The first integer is the number of "DONE" todos, the second integer is the total todos
938+
function Headline:_get_todo_progress()
939+
-- Count done children headlines and total children with TODO keywords
940+
local children = self:get_child_headlines()
941+
local headlines_with_todo = vim.tbl_filter(function(h)
942+
local todo, _, _ = h:get_todo()
943+
return todo ~= nil
944+
end, children)
945+
946+
local dones = vim.tbl_filter(function(h)
947+
return h:is_done()
948+
end, headlines_with_todo)
949+
950+
if #headlines_with_todo == 0 then
951+
return
952+
end
953+
954+
return { #dones, #headlines_with_todo }
955+
end
956+
957+
function Headline:update_cookie()
958+
-- Update cookie state from a check box state change
959+
960+
-- Return early if the headline doesn't have a cookie
961+
local cookie = self:get_cookie()
962+
if not cookie then
963+
return self
964+
end
965+
966+
local section = self:node():parent()
967+
if not section then
968+
return self
969+
end
970+
971+
local progress = self:_get_checkbox_progress()
972+
if not progress then
973+
return self
974+
end
975+
local num_checked_boxes, num_boxes = unpack(progress)
976+
936977
-- Set the cookie
937978
return self:_set_cookie(cookie, num_checked_boxes, num_boxes)
938979
end
@@ -946,19 +987,15 @@ function Headline:update_todo_cookie()
946987
return self
947988
end
948989

949-
-- Count done children headlines and total children with TODO keywords
950-
local children = self:get_child_headlines()
951-
local headlines_with_todo = vim.tbl_filter(function(h)
952-
local todo, _, _ = h:get_todo()
953-
return todo ~= nil
954-
end, children)
990+
local progress = self:_get_todo_progress()
991+
if not progress then
992+
return self
993+
end
955994

956-
local dones = vim.tbl_filter(function(h)
957-
return h:is_done()
958-
end, headlines_with_todo)
995+
local dones, headlines_with_todo = unpack(progress)
959996

960997
-- Set the cookie
961-
return self:_set_cookie(cookie, #dones, #headlines_with_todo)
998+
return self:_set_cookie(cookie, dones, headlines_with_todo)
962999
end
9631000

9641001
function Headline:update_parent_cookie()

lua/orgmode/org/global.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ local build = function(orgmode)
9898
indent_mode = function()
9999
require('orgmode.ui.virtual_indent').toggle_buffer_indent_mode()
100100
end,
101+
cookie_mode = function()
102+
local virtcookie = require('orgmode.ui.virtcookie').get()
103+
if virtcookie then
104+
virtcookie:toggle()
105+
end
106+
end,
101107
}
102108

103109
_G.Org = OrgGlobal

0 commit comments

Comments
 (0)