vimwiki

Personal wiki for vim
git clone https://github.com/vimwiki/vimwiki.git
Log | Files | Refs | README | LICENSE

commit a9f21c6d4a8cedc58971d57df0c2bd2dea8c4d4c
parent 61093f4f2aa2748a7d7fcd8ea7a4542f8723cdfb
Author: Michael F. Schönitzer <michael@schoenitzer.de>
Date:   Mon,  8 Jun 2020 14:31:35 +0200

Functions to remove all todo items that are done (#906)

Add function VimwikiRemoveDone that will delete lines with todo list items marked as done. Works on ranges as well as without range on the current list.

Co-authored-by: Tinmarino <tinmarino@gmail.com>
Diffstat:
Mautoload/vimwiki/lst.vim | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/vimwiki.txt | 12++++++++++++
Mftplugin/vimwiki.vim | 1+
Atest/list_clean.vader | 199+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 329 insertions(+), 0 deletions(-)

diff --git a/autoload/vimwiki/lst.vim b/autoload/vimwiki/lst.vim @@ -155,6 +155,24 @@ function! s:line_has_marker(lnum) abort endfunction +" Remove a list item and it's children (recursive) +function! s:remove_including_children(item) + let num_removed_lines = 1 + let child = s:get_first_child(a:item) + while child.type != 0 + let num_removed_lines += s:remove_including_children(child) + let child = s:get_first_child(a:item) + endwhile + exec a:item.lnum.'delete _' + return num_removed_lines +endfunction + + +function! s:is_done(item) + return a:item.type != 0 && a:item.cb !=# '' && s:get_rate(a:item) == 100 +endfunction + + " --------------------------------------------------------- " get properties of a list item " --------------------------------------------------------- @@ -1085,6 +1103,105 @@ function! vimwiki#lst#remove_cb_in_list() abort endfunction +" Iterate over given todo list and remove all task that are done +" If recursive is true, child items will be checked too +function! s:remove_done_in_list(item, recursive) + " Clause non-null item type + if a:item.type == 0 + return + endif + + " Recurse self on list item + let first_item = s:get_first_item_in_list(a:item, 0) + let total_lines_removed = 0 + let cur_item = first_item + while 1 + let next_item = s:get_next_list_item(cur_item, 0) + if s:is_done(cur_item) + let lines_removed = s:remove_including_children(cur_item) + elseif a:recursive + let lines_removed = s:remove_done_in_list(s:get_first_child(cur_item), a:recursive) + else + let lines_removed = 0 + endif + let total_lines_removed += lines_removed + + if next_item.type == 0 + break + else + let next_item.lnum -= lines_removed + let cur_item = next_item + endif + endwhile + + " Update state of parent item (percentage of done) + call s:update_state(s:get_parent(first_item)) + return total_lines_removed +endfunction + + +" Iterate over the list that the cursor is positioned in +" and remove all lines of task that are done. +" If recursive is true, child items will be checked too +function! vimwiki#lst#remove_done_in_current_list(recursive) + let item = s:get_corresponding_item(line('.')) + call s:remove_done_in_list(item, a:recursive) +endfunction + + +" Remove selected lines if they contain a task that is done +function! vimwiki#lst#remove_done_in_range(first_line, last_line) + let first_item = s:get_corresponding_item(a:first_line) + let last_item = s:get_corresponding_item(a:last_line) + + " Clause non-null first and last type item + if first_item.type == 0 || last_item.type == 0 + return + endif + + " For each line, delete done tasks + let parent_items_of_lines = [] + let cur_ln = first_item.lnum + let end_ln = last_item.lnum + while cur_ln > 0 && cur_ln <= end_ln + let cur_item = s:get_item(cur_ln) + if s:is_done(cur_item) + let cur_parent_item = s:get_parent(cur_item) + if index(parent_items_of_lines, cur_parent_item) == -1 + call insert(parent_items_of_lines, cur_parent_item) + endif + exe cur_ln.'delete _' + let cur_ln -= 1 + let end_ln -= 1 + endif + let cur_ln = s:get_next_line(cur_ln) + endwhile + + " Update all parent state (percentage of done) + for parent_item in parent_items_of_lines + call s:update_state(parent_item) + endfor +endfunction + + +" wrapper function to distinguish between function used with a range or not +" vim 8.0.1089 and newer and corresponding neovim versions allow to use <range> to distinguish if +" the function has been called with a range. For older versions we use remove_done_in_range if +" first and last line are identical, which means there was either no range or the range was within +" one line. +function! vimwiki#lst#remove_done(recursive, range, first_line, last_line) + if a:range ==# '<range>' + let range = a:first_line != a:last_line + else + let range = a:range > 0 + endif + if range + call vimwiki#lst#remove_done_in_range(a:first_line, a:last_line) + else + call vimwiki#lst#remove_done_in_current_list(a:recursive) + endif +endfunction + " --------------------------------------------------------- " change the level of list items diff --git a/doc/vimwiki.txt b/doc/vimwiki.txt @@ -799,6 +799,18 @@ Vimwiki file. *:VimwikiRenameFile* Rename the wiki page you are in. +*:VimwikiRemoveDone* + With range: Remove all lines that have a checked |vimwiki-todo-lists| checkbox + + Otherwise: + Remove all lines in the current todo-list that have a checked box. This is + applied to the list in which the cursor is in, as well as all its sublists. + The status of parents is updated accordingly. + If you want to remove only items of the current nesting level, (re)define + a command that calls the same function with `0` as first argument: > + :command! -buffer -range VimwikiRemoveDone call + \ vimwiki#lst#remove_done(0, "<range>", <line1>, <line2>) +< *:VimwikiNextTask* Jump to the next unfinished task in the current wiki page. diff --git a/ftplugin/vimwiki.vim b/ftplugin/vimwiki.vim @@ -297,6 +297,7 @@ command! -buffer VimwikiRemoveCBInList call vimwiki#lst#remove_cb_in_list() command! -buffer VimwikiRenumberList call vimwiki#lst#adjust_numbered_list() command! -buffer VimwikiRenumberAllLists call vimwiki#lst#adjust_whole_buffer() command! -buffer VimwikiListToggle call vimwiki#lst#toggle_list_item() +command! -buffer -range VimwikiRemoveDone call vimwiki#lst#remove_done(1, "<range>", <line1>, <line2>) " table commands command! -buffer -nargs=* VimwikiTable call vimwiki#tbl#create(<f-args>) diff --git a/test/list_clean.vader b/test/list_clean.vader @@ -0,0 +1,199 @@ +Include: vader_includes/vader_setup.vader + +Given vimwiki (simple list): + * [X] Done 1 + * [ ] Todo 1 + * [X] Done 2 + * [ ] Todo 2 + +Execute (Set syntax to default): + call SetSyntax('default') + +Do (clean done, without recursion): + :call vimwiki#lst#remove_done_in_current_list(0)\<Enter> + +Expect (two removed): + * [ ] Todo 1 + * [ ] Todo 2 + +Given vimwiki (simple list): + * [X] Done 1 + * [ ] Todo 1 + * [X] Done 2 + * [ ] Todo 2 + +Do (clean done with recursion, function): + :call vimwiki#lst#remove_done_in_current_list(1)\<Enter> + +Expect (two removed): + * [ ] Todo 1 + * [ ] Todo 2 + +Given vimwiki (simple list): + * [X] Done 1 + * [ ] Todo 1 + * [X] Done 2 + * [ ] Todo 2 + +Do (clean done with recursion, command): + :VimwikiRemoveDone\<Enter> + +Expect (two removed): + * [ ] Todo 1 + * [ ] Todo 2 + +Given vimwiki (with sub items): + * [X] Done 1 + * [X] Subdone 1 + * [ ] Todo 1 + * [o] Done 2 + * [X] Subdone1 + * [ ] Subtodo + * [ ] Todo 2 + +Do (clean done, without recursion): + :call vimwiki#lst#remove_done_in_current_list(0)\<Enter> + +Expect (first removed): + * [ ] Todo 1 + * [o] Done 2 + * [X] Subdone1 + * [ ] Subtodo + * [ ] Todo 2 + +Given vimwiki (with sub items): + * [ ] Todo 1 + * [o] Done 2 + * [X] Subdone1 + * [ ] Subtodo + * [ ] Todo 2 + +Do (clean done, with recursion): + :call vimwiki#lst#remove_done_in_current_list(1)\<Enter> + +Expect (all removed): + * [ ] Todo 1 + * [ ] Done 2 + * [ ] Subtodo + * [ ] Todo 2 + +Given vimwiki (nested list with space and code): + * [X] Done 1 + * [ ] Todo 1 + + * [ ] Todo Post space + * [X] Done Post space + + * [ ] Todo code + {{{code + * [X] print "hello, world" + }}} + + * [ ] Post code Todo + * [X] Done Sub-child + * [X] Sub-sub-child + * Without cb + * [X] Post code Done + * [X] Done Sub-child + * [X] Sub-sub-child + * Without cb + +Do (clean done, without recursion): + :call vimwiki#lst#remove_done_in_current_list(0)\<Enter> + +Expect (removed): + * [ ] Todo 1 + + * [ ] Todo Post space + + * [ ] Todo code + {{{code + * [X] print "hello, world" + }}} + + * [ ] Post code Todo + * [X] Done Sub-child + * [X] Sub-sub-child + * Without cb + +Given vimwiki (nested list with space and code): + * [X] Done 1 + * [ ] Todo 1 + + * [ ] Todo Post space + * [X] Done Post space + + * [ ] Todo code + {{{code + * [X] print "hello, world" + }}} + + * [ ] Post code Todo + * [X] Done Sub-child + * [X] Sub-sub-child + * Without cb + * [X] Post code Done + * [X] Done Sub-child + * [X] Sub-sub-child + * Without cb + +Do (clean done, with recursion): + :call vimwiki#lst#remove_done_in_current_list(1)\<Enter> + +Expect (removed): + * [ ] Todo 1 + + * [ ] Todo Post space + + * [ ] Todo code + {{{code + * [X] print "hello, world" + }}} + + * [ ] Post code Todo + +Given vimwiki (two lists): + * [X] Done 1 + * [ ] Todo 1 + + Line in between. + + * [ ] Todo Post space + * [X] Done Post space + +Do (clean done, with recursion): + :call vimwiki#lst#remove_done_in_current_list(1)\<Enter> + +Expect (only first is removed): + * [ ] Todo 1 + + Line in between. + + * [ ] Todo Post space + * [X] Done Post space + +Given vimwiki (list): + * [X] Done 1 + * [ ] Todo 1 + + Line in between. + + * [X] Done 2 + * [X] Done 3 + * [ ] Todo 2 + * [X] Done 4 + +Do (clean done, with range): + :1,6VimwikiRemoveDone\<Enter> + +Expect (only first is removed): + * [ ] Todo 1 + + Line in between. + + * [X] Done 3 + * [ ] Todo 2 + * [X] Done 4 + + +Include: vader_includes/vader_teardown.vader