@@ -779,6 +779,85 @@ fun! s:set_child_checkboxes(lnum, checked)
779779 endif
780780endfun
781781
782+ " Recompute partial checkboxes of a full checkbox tree given the root lnum
783+ fun ! s: recompute_checkbox_tree (lnum)
784+ if ! g: bullets_nested_checkboxes
785+ return
786+ endif
787+
788+ let l: indent = indent (a: lnum )
789+ let l: bullet = s: closest_bullet_types (a: lnum , l: indent )
790+ let l: bullet = s: resolve_bullet_type (l: bullet )
791+
792+ if l: bullet .bullet_type !=# ' chk'
793+ return
794+ endif
795+
796+ " recursively recompute checkbox tree for all children, then finally self
797+
798+ let l: children = s: get_children_line_numbers (a: lnum )
799+ for l: child_nr in l: children
800+ " nb: this skips 'grandchildren' checkboxes (i.e., children who aren't
801+ " checkboxes but have checkbox children themselves), but those grandkids
802+ " will be targeted by s:recompute_checkboxes_in_range anyway
803+ call s: recompute_checkbox_tree (l: child_nr )
804+ endfor
805+
806+
807+ if empty (l: children )
808+ " if no children, preserve previous checked state
809+ " partially completed checkboxes become unchecked
810+ if empty (l: bullet ) || ! has_key (l: bullet , ' checkbox_marker' )
811+ return
812+ endif
813+
814+ let l: checkbox_markers = split (g: bullets_checkbox_markers , ' \zs' )
815+ let l: partial_markers = join (l: checkbox_markers [1 :-2 ], ' ' )
816+
817+ if l: bullet .checkbox_marker = ~# ' \v[' . l: partial_markers . ' ]'
818+ call s: set_checkbox (a: lnum , l: checkbox_markers [0 ])
819+ endif
820+ else
821+ " if children exist, recompute this checkbox status
822+ let l: first_child = l: children [0 ]
823+ let l: completion_marker = s: sibling_checkbox_status (l: first_child )
824+ call s: set_checkbox (a: lnum , l: completion_marker )
825+ endif
826+ endfun
827+
828+ fun ! s: recompute_checkboxes_in_range (start , end )
829+ if ! g: bullets_nested_checkboxes
830+ return
831+ endif
832+
833+ call s: enable_bullet_cache ()
834+ for l: nr in range (a: start , a: end )
835+ " find all bullets who do not have a checkbox parent
836+ let l: parent = s: get_parent (l: nr )
837+ if ! empty (l: parent ) && l: parent .bullet_type == # ' chk'
838+ continue
839+ end
840+
841+ call s: recompute_checkbox_tree (l: nr )
842+ endfor
843+ call s: disable_bullet_cache ()
844+ endfun
845+
846+ " Recomputes checkboxes for the whole list containing the cursor.
847+ fun ! s: recompute_checkboxes ()
848+ if ! g: bullets_nested_checkboxes
849+ return
850+ endif
851+
852+ call s: enable_bullet_cache ()
853+ let l: first_line = s: first_bullet_line (line (' .' ))
854+ let l: last_line = s: last_bullet_line (line (' .' ))
855+ if l: first_line > 0 && l: last_line > 0
856+ call s: recompute_checkboxes_in_range (l: first_line , l: last_line )
857+ endif
858+ call s: disable_bullet_cache ()
859+ endfun
860+
782861command ! SelectCheckboxInside call <SID> select_checkbox (1 )
783862command ! SelectCheckbox call <SID> select_checkbox (0 )
784863command ! ToggleCheckbox call <SID> toggle_checkboxes_nested ()
@@ -961,6 +1040,7 @@ endfun
9611040
9621041command ! -range =% RenumberSelection call <SID> renumber_selection ()
9631042command ! RenumberList call <SID> renumber_whole_list ()
1043+ command ! RecomputeCheckboxes call <SID> recompute_checkboxes ()
9641044
9651045" --------------------------------------------------------- }}}
9661046
@@ -1107,6 +1187,9 @@ nnoremap <silent> <Plug>(bullets-renumber) :RenumberList<cr>
11071187" Toggle checkbox
11081188nnoremap <silent> <Plug> (bullets-toggle-checkbox) :ToggleCheckbox<cr>
11091189
1190+ " Recompute checkbox list
1191+ nnoremap <silent> <Plug> (bullets-recompute-checkboxes) :RecomputeCheckboxes<cr>
1192+
11101193" Promote and Demote outline level
11111194inoremap <silent> <Plug> (bullets-demote) <C-o> :BulletDemote<cr>
11121195nnoremap <silent> <Plug> (bullets-demote) :BulletDemote<cr>
0 commit comments